home *** CD-ROM | disk | FTP | other *** search
/ Amiga Plus Special 23 / AMIGAplus Sonderheft 23 (2000)(Falke)(DE)[!].iso / Tools / Text-Viewer / MSWordView / notes / wmf / gimpwmf.c next >
Encoding:
C/C++ Source or Header  |  1999-11-06  |  70.9 KB  |  2,482 lines

  1. /* WMF plug-in for The GIMP
  2.  * Copyright (C) 1998 Tor Lillqvist
  3.  *
  4.  * This program is free software; you can redistribute it and/or modify
  5.  * it under the terms of the GNU General Public License as published by
  6.  * the Free Software Foundation; either version 2 of the License, or
  7.  * (at your option) any later version.
  8.  *
  9.  * This program is distributed in the hope that it will be useful,
  10.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  12.  * GNU General Public License for more details.
  13.  *
  14.  * You should have received a copy of the GNU General Public License
  15.  * along with this program; if not, write to the Free Software
  16.  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  17.  *
  18.  * See http://www.iki.fi/tml/gimp/wmf/
  19.  */
  20.  
  21. #define VERSION "1998-11-06"
  22.  
  23. #include <stdio.h>
  24. #include <stdlib.h>
  25. #include <string.h>
  26. #include <math.h>
  27.  
  28. #include "gtk/gtk.h"
  29. #include "libgimp/gimp.h"
  30.  
  31. char *g_strdown(char *in);
  32.  
  33. typedef guchar BYTE;
  34. typedef guint16 WORD;
  35. typedef guint32 DWORD;
  36.  
  37. typedef gint16 SHORT;
  38. typedef gint32 LONG;
  39.  
  40. /* The following information is from O'Reilly's updates to the
  41.  * Encyclopedia of Graphics File Formats,
  42.  * http://www.ora.com/centers/gff/formats/micmeta/index.htm
  43.  */
  44.  
  45. typedef struct _WindowsMetaHeader
  46. {
  47.     WORD  FileType;       /* Type of metafile (0=memory, 1=disk) */
  48.     WORD  HeaderSize;     /* Size of header in WORDS (always 9) */
  49.     WORD  Version;        /* Version of Microsoft Windows used */
  50.     DWORD FileSize;       /* Total size of the metafile in WORDs */
  51.     WORD  NumOfObjects;   /* Number of objects in the file */
  52.     DWORD MaxRecordSize;  /* The size of largest record in WORDs */
  53.     WORD  NumOfParams;    /* Not Used (always 0) */
  54. } WMFHEAD;
  55.  
  56. #define SIZE_WMFHEAD 18
  57.  
  58. typedef struct _PlaceableMetaHeader
  59. {
  60.     DWORD Key;           /* Magic number (always 9AC6CDD7h) */
  61.     WORD  Handle;        /* Metafile HANDLE number (always 0) */
  62.     SHORT Left;          /* Left coordinate in metafile units */
  63.     SHORT Top;           /* Top coordinate in metafile units */
  64.     SHORT Right;         /* Right coordinate in metafile units */
  65.     SHORT Bottom;        /* Bottom coordinate in metafile units */
  66.     WORD  Inch;          /* Number of metafile units per inch */
  67.     DWORD Reserved;      /* Reserved (always 0) */
  68.     WORD  Checksum;      /* Checksum value for previous 10 WORDs */
  69. } PLACEABLEMETAHEADER;
  70.  
  71. #define SIZE_PLACEABLEMETAHEADER 22
  72.  
  73. typedef struct _Clipboard16MetaHeader
  74. {
  75.     SHORT MappingMode; /* Units used to playback metafile */
  76.     SHORT Width;       /* Width of the metafile */
  77.     SHORT Height;      /* Height of the metafile */
  78.     WORD  Handle;      /* Handle to the metafile in memory */
  79. } CLIPBOARD16METAHEADER;
  80.  
  81. #define SIZE_CLIPBOARD16METAHEADER 8
  82.  
  83. typedef struct _Clipboard32MetaHeader
  84. {
  85.     LONG  MappingMode; /* Units used to playback metafile */
  86.     LONG  Width;       /* Width of the metafile */
  87.     LONG  Height;      /* Height of the metafile */
  88.     DWORD Handle;      /* Handle to the metafile in memory */
  89. } CLIPBOARD32METAHEADER;
  90.  
  91. #define SIZE_CLIPBOARD32METAHEADER 16
  92.  
  93. typedef struct _EnhancedMetaHeader
  94. {
  95.     DWORD RecordType;       /* Record type */
  96.     DWORD RecordSize;       /* Size of the record in bytes */
  97.     LONG  BoundsLeft;       /* Left inclusive bounds */
  98.     LONG  BoundsRight;      /* Right inclusive bounds */
  99.     LONG  BoundsTop;        /* Top inclusive bounds */
  100.     LONG  BoundsBottom;     /* Bottom inclusive bounds */
  101.     LONG  FrameLeft;        /* Left side of inclusive picture frame */
  102.     LONG  FrameRight;       /* Right side of inclusive picture frame */
  103.     LONG  FrameTop;         /* Top side of inclusive picture frame */
  104.     LONG  FrameBottom;      /* Bottom side of inclusive picture frame */
  105.     DWORD Signature;        /* Signature ID (always 0x464D4520) */
  106.     DWORD Version;          /* Version of the metafile */
  107.     DWORD Size;             /* Size of the metafile in bytes */
  108.     DWORD NumOfRecords;     /* Number of records in the metafile */
  109.     WORD  NumOfHandles;     /* Number of handles in the handle table */
  110.     WORD  Reserved;         /* Not used (always 0) */
  111.     DWORD SizeOfDescrip;    /* Size of description string in WORDs */
  112.     DWORD OffsOfDescrip;    /* Offset of description string in metafile */
  113.     DWORD NumPalEntries;    /* Number of color palette entries */
  114.     LONG  WidthDevPixels;   /* Width of reference device in pixels */
  115.     LONG  HeightDevPixels;  /* Height of reference device in pixels */
  116.     LONG  WidthDevMM;       /* Width of reference device in millimeters */
  117.     LONG  HeightDevMM;      /* Height of reference device in millimeters */
  118. } ENHANCEDMETAHEADER;
  119.  
  120. #define SIZE_ENHANCEDMETAHEADER 88
  121.  
  122. typedef struct _StandardMetaRecord
  123. {
  124.     DWORD Size;          /* Total size of the record in WORDs */
  125.     WORD  Function;      /* Function number (defined in WINDOWS.H) */
  126. #if DOCUMENTATION_ONLY_ILLEGAL_C
  127.     WORD  Parameters[]; /* Parameter values passed to function */
  128. #endif
  129. } WMFRECORD;
  130.  
  131. #define SIZE_WMFRECORD 6
  132.  
  133. #define EndOfFile        0x0000
  134.  
  135. #define AbortDoc        0x0052
  136. #define Arc            0x0817
  137. #define Chord            0x0830
  138. #define Ellipse            0x0418
  139. #define EndDoc            0x005E
  140. #define EndPage            0x0050
  141. #define ExcludeClipRect        0x0415
  142. #define ExtFloodFill        0x0548
  143. #define FillRegion        0x0228
  144. #define FloodFill        0x0419
  145. #define FrameRegion        0x0429
  146. #define IntersectClipRect    0x0416
  147. #define InvertRegion        0x012A
  148. #define LineTo            0x0213
  149. #define MoveTo            0x0214
  150. #define OffsetClipRgn        0x0220
  151. #define OffsetViewportOrg    0x0211
  152. #define OffsetWindowOrg        0x020F
  153. #define PaintRegion        0x012B
  154. #define PatBlt            0x061D
  155. #define Pie            0x081A
  156. #define RealizePalette        0x0035
  157. #define Rectangle        0x041B
  158. #define ResetDc            0x014C
  159. #define ResizePalette        0x0139
  160. #define RestoreDC        0x0127
  161. #define RoundRect        0x061C
  162. #define SaveDC            0x001E
  163. #define ScaleViewportExt    0x0412
  164. #define ScaleWindowExt        0x0410
  165. #define SelectClipRegion    0x012C
  166. #define SelectObject        0x012D
  167. #define SelectPalette        0x0234
  168. #define SetBkColor        0x0201
  169. #define SetBkMode        0x0102
  170. #define SetDibToDev        0x0d33
  171. #define SetMapMode        0x0103
  172. #define SetMapperFlags        0x0231
  173. #define SetPalEntries        0x0037
  174. #define SetPixel        0x041F
  175. #define SetPolyFillMode        0x0106
  176. #define SetRelabs        0x0105
  177. #define SetROP2            0x0104
  178. #define SetStretchBltMode    0x0107
  179. #define SetTextAlign        0x012E
  180. #define SetTextCharExtra    0x0108
  181. #define SetTextColor        0x0209
  182. #define SetTextJustification    0x020A
  183. #define SetViewportExt        0x020E
  184. #define SetViewportOrg        0x020D
  185. #define SetWindowExt        0x020C
  186. #define SetWindowOrg        0x020B
  187. #define StartDoc        0x014D
  188. #define StartPage        0x004F
  189.  
  190. #define AnimatePalette        0x0436
  191. #define BitBlt            0x0922
  192. #define CreateBitmap        0x06FE
  193. #define CreateBitmapIndirect    0x02FD
  194. #define CreateBrush        0x00F8
  195. #define CreateBrushIndirect    0x02FC
  196. #define CreateFontIndirect    0x02FB
  197. #define CreatePalette        0x00F7
  198. #define CreatePatternBrush    0x01F9
  199. #define CreatePenIndirect    0x02FA
  200. #define CreateRegion        0x06FF
  201. #define DeleteObject        0x01F0
  202. #define DibBitblt        0x0940
  203. #define DibCreatePatternBrush    0x0142
  204. #define DibStretchBlt        0x0B41
  205. #define DrawText        0x062F
  206. #define Escape            0x0626
  207. #define ExtTextOut        0x0A32
  208. #define Polygon            0x0324
  209. #define PolyPolygon        0x0538
  210. #define Polyline        0x0325
  211. #define TextOut            0x0521
  212. #define StretchBlt        0x0B23
  213. #define StretchDIBits        0x0F43
  214.  
  215. typedef struct _RGBTriple
  216. {
  217.     BYTE Red;
  218.     BYTE Green;
  219.     BYTE Blue;
  220. } RGBTRIPLE;
  221.  
  222. typedef struct _BitBltRecord
  223. {
  224.     DWORD     Size;             /* Total size of the record in WORDs */
  225.     WORD      Function;         /* Function number (0x0922) */
  226.     WORD      RasterOp;         /* High-order word for the raster operation */
  227.     WORD      YSrcOrigin;       /* Y-coordinate of the source origin */
  228.     WORD      XSrcOrigin;       /* X-coordinate of the source origin */
  229.     WORD      YDest;            /* Destination width */
  230.     WORD      XDest;            /* Destination height */
  231.     WORD      YDestOrigin;      /* Y-coordinate of the destination origin */
  232.     WORD      XDestOrigin;      /* X-coordinate of the destination origin */
  233.     /* DDB Bitmap */
  234.     DWORD     Width;            /* Width of bitmap in pixels */
  235.     DWORD     Height;           /* Height of bitmap in scan lines */
  236.     DWORD     BytesPerLine;     /* Number of bytes in each scan line */
  237.     WORD      NumColorPlanes;   /* Number of color planes in the bitmap */
  238.     WORD      BitsPerPixel;     /* Number of bits in each pixel */
  239. #if DOCUMENTATION_ONLY_ILLEGAL_C
  240.     RGBTRIPLE Bitmap[];         /* Bitmap data */
  241. #endif
  242. } BITBLTRECORD;
  243.  
  244. typedef struct _RGBQuad
  245. {
  246.     BYTE Red;
  247.     BYTE Green;
  248.     BYTE Blue;
  249.     BYTE Reserved;
  250. } RGBQUAD;
  251.  
  252. typedef struct _DibBitBltRecord
  253. {
  254.     DWORD   Size;             /* Total size of the record in WORDs */
  255.     WORD    Function;         /* Function number (0x0940) */
  256.     WORD    RasterOp;         /* High-order word for the raster operation */
  257.     WORD    YSrcOrigin;       /* Y-coordinate of the source origin */
  258.     WORD    XSrcOrigin;       /* X-coordinate of the source origin */
  259.     WORD    YDest;            /* Destination width */
  260.     WORD    XDest;            /* Destination height */
  261.     WORD    YDestOrigin;      /* Y-coordinate of the destination origin */
  262.     WORD    XDestOrigin;      /* X-coordinate of the destination origin */
  263.     /* DIB Bitmap */
  264.     DWORD   Width;            /* Width of bitmap in pixels */
  265.     DWORD   Height;           /* Height of bitmap in scan lines */
  266.     DWORD   BytesPerLine;     /* Number of bytes in each scan line */
  267.     WORD    NumColorPlanes;   /* Number of color planes in the bitmap */
  268.     WORD    BitsPerPixel;     /* Number of bits in each pixel */
  269.     DWORD   Compression;      /* Compression type */
  270.     DWORD   SizeImage;        /* Size of bitmap in bytes */
  271.     LONG    XPelsPerMeter;    /* Width of image in pixels per meter */
  272.     LONG    YPelsPerMeter;    /* Height of image in pixels per meter */
  273.     DWORD   ClrUsed;          /* Number of colors used */
  274.     DWORD   ClrImportant;     /* Number of important colors */
  275. #if DOCUMENTATION_ONLY_ILLEGAL_C
  276.     RGBQUAD Bitmap[];         /* Bitmap data */
  277. #endif
  278. } DIBBITBLTRECORD;
  279.  
  280. typedef struct _EnhancedMetaRecord
  281. {
  282.     DWORD Function;      /* Function number (defined in WINGDI.H) */
  283.     DWORD Size;          /* Total size of the record in WORDs */
  284. #if DOCUMENTATION_ONLY_ILLEGAL_C
  285.     DWORD Parameters[];   /* Parameter values passed to GDI function */
  286. #endif
  287. } EMFRECORD;
  288.  
  289. #define EMR_ABORTPATH        68
  290. #define EMR_POLYLINE        4
  291. #define EMR_ANGLEARC        41
  292. #define EMR_POLYLINE16        87
  293. #define EMR_ARC            45
  294. #define EMR_POLYLINETO        6
  295. #define EMR_ARCTO        55
  296. #define EMR_POLYLINETO16    89
  297. #define EMR_BEGINPATH        59
  298. #define EMR_POLYPOLYGON        8
  299. #define EMR_BITBLT        76
  300. #define EMR_POLYPOLYGON16    91
  301. #define EMR_CHORD        46
  302. #define EMR_POLYPOLYLINE    7
  303. #define EMR_CLOSEFIGURE        61
  304. #define EMR_POLYPOLYLINE16    90
  305. #define EMR_CREATEBRUSHINDIRECT    39
  306. #define EMR_POLYTEXTOUTA    96
  307. #define EMR_CREATEDIBPATTERNBRUSHPT 94
  308. #define EMR_POLYTEXTOUTW    97
  309. #define EMR_CREATEMONOBRUSH    93
  310. #define EMR_REALIZEPALETTE    52
  311. #define EMR_CREATEPALETTE    49
  312. #define EMR_RECTANGLE        43
  313.  
  314. #define EMR_CREATEPEN        38
  315. #define EMR_RESIZEPALETTE    51
  316. #define EMR_DELETEOBJECT    40
  317. #define EMR_RESTOREDC        34
  318. #define EMR_ELLIPSE        42
  319. #define EMR_ROUNDRECT        44
  320. #define EMR_ENDPATH        60
  321. #define EMR_SAVEDC        33
  322. #define EMR_EOF            14
  323. #define EMR_SCALEVIEWPORTEXTEX    31
  324. #define EMR_EXCLUDECLIPRECT    29
  325. #define EMR_SCALEWINDOWEXTEX    32
  326. #define EMR_EXTCREATEFONTINDIRECTW 82
  327. #define EMR_SELECTCLIPPATH    67
  328. #define EMR_EXTCREATEPEN    95
  329. #define EMR_SELECTOBJECT    37
  330. #define EMR_EXTFLOODFILL    53
  331. #define EMR_SELECTPALETTE    48
  332. #define EMR_EXTSELECTCLIPRGN    75
  333. #define EMR_SETARCDIRECTION    57
  334. #define EMR_EXTTEXTOUTA        83
  335. #define EMR_SETBKCOLOR        25
  336.  
  337. #define EMR_EXTTEXTOUTW        84
  338. #define EMR_SETBKMODE        18
  339. #define EMR_FILLPATH        62
  340. #define EMR_SETBRUSHORGEX    13
  341. #define EMR_FILLRGN        71
  342. #define EMR_SETCOLORADJUSTMENT    23
  343. #define EMR_FLATTENPATH        65
  344. #define EMR_SETDIBITSTODEVICE    80
  345. #define EMR_FRAMERGN        72
  346. #define EMR_SETMAPMODE        17
  347. #define EMR_GDICOMMENT        70
  348. #define EMR_SETMAPPERFLAGS    16
  349. #define EMR_HEADER        1
  350. #define EMR_SETMETARGN        28
  351. #define EMR_INTERSECTCLIPRECT    30
  352. #define EMR_SETMITERLIMIT    58
  353. #define EMR_INVERTRGN        73
  354. #define EMR_SETPALETTEENTRIES    50
  355. #define EMR_LINETO        54
  356. #define EMR_SETPIXELV        15
  357. #define EMR_MASKBLT        78
  358. #define EMR_SETPOLYFILLMODE    19
  359. #define EMR_MODIFYWORLDTRANSFORM 36
  360. #define EMR_SETROP2        20
  361.  
  362. #define EMR_MOVETOEX        27
  363. #define EMR_SETSTRETCHBLTMODE    21
  364. #define EMR_OFFSETCLIPRGN    26
  365. #define EMR_SETTEXTALIGN    22
  366. #define EMR_PAINTRGN        74
  367. #define EMR_SETTEXTCOLOR    24
  368. #define EMR_PIE            47
  369. #define EMR_SETVIEWPORTEXTEX    11
  370. #define EMR_PLGBLT        79
  371. #define EMR_SETVIEWPORTORGEX    12
  372. #define EMR_POLYBEZIER        2
  373. #define EMR_SETWINDOWEXTEX    9
  374. #define EMR_POLYBEZIER16    85
  375. #define EMR_SETWINDOWORGEX    10
  376. #define EMR_POLYBEZIERTO    5
  377. #define EMR_SETWORLDTRANSFORM    35
  378. #define EMR_POLYBEZIERTO16    88
  379. #define EMR_STRETCHBLT        77
  380. #define EMR_POLYDRAW        56
  381. #define EMR_STRETCHDIBITS    81
  382. #define EMR_POLYDRAW16        92
  383. #define EMR_STROKEANDFILLPATH    63
  384.  
  385. #define EMR_POLYGON        3
  386. #define EMR_STROKEPATH        64
  387. #define EMR_POLYGON16        86
  388. #define EMR_WIDENPATH        66
  389.  
  390. typedef struct _PaletteEntry
  391. {
  392.     BYTE Red;       /* Red component value */
  393.     BYTE Green;     /* Green component value */
  394.     BYTE Blue;      /* Blue component value */
  395.     BYTE Flags;     /* Flag values */
  396. } PALENT;
  397.  
  398. typedef struct _EndOfRecord
  399. {
  400.     DWORD  Function;        /* End Of Record ID (14) */
  401.     DWORD  Size;            /* Total size of the record in WORDs */
  402.     DWORD  NumPalEntries;   /* Number of color palette entries */
  403.     DWORD  OffPalEntries;   /* Offset of color palette entries */
  404. #if DOCUMENTATION_ONLY_ILLEGAL_C
  405.     PALENT Palette[];       /* The color palette data */
  406.     DWORD  OffToEOF;        /* Offset to beginning of this record */
  407. #endif
  408. } ENDOFRECORD;
  409.  
  410. typedef struct _GdiCommentRecord
  411. {
  412.     DWORD   Function;      /* GDI Comment ID (70) */
  413.     DWORD   Size;          /* Total size of the record in WORDs */
  414.     DWORD   SizeOfData;    /* Size of comment data in bytes */
  415. #if DOCUMENTATION_ONLY_ILLEGAL_C
  416.     BYTE    Data[];        /* Comment data */        
  417. #endif
  418. } GDICOMMENTRECORD;
  419.  
  420. typedef struct _GdiCommentMetafile
  421. {
  422.     DWORD Identifier;       /* Comment ID (0x43494447) */
  423.     DWORD Comment;          /* Metafile ID (0x80000001) */
  424.     DWORD Version;          /* Version of the metafile */
  425.     DWORD Checksum;         /* Checksum value of the metafile */
  426.     DWORD Flags;            /* Flags (always 0) */
  427.     DWORD Size;             /* Size of the metafile data in bytes */
  428. } GDICOMMENTMETAFILE;
  429.  
  430. typedef struct _GdiCommentBeginGroup
  431. {
  432.     DWORD Identifier;       /* Comment ID (0x43494447) */
  433.     DWORD Comment;          /* BeginGroup ID (0x00000002) */
  434.     LONG  BoundsLeft;       /* Left side of bounding rectangle */
  435.     LONG  BoundsRight;      /* Right side of bounding rectangle */
  436.     LONG  BoundsTop;        /* Top side of bounding rectangle */
  437.     LONG  BoundsBottom;     /* Bottom side of bounding rectangle */
  438.     DWORD SizeOfDescrip;    /* Number of characters in the description */     
  439. } GDICOMMENTBEGINGROUP;
  440.  
  441. typedef struct _GdiCommentEndGroup
  442. {
  443.     DWORD Identifier;       /* Comment ID (0x43494447) */
  444.     DWORD Comment;          /* EndGroup ID (0x00000003) */
  445. } GDICOMMENTENDGROUP;
  446.  
  447. typedef struct _EmrFormat
  448. {
  449.     DWORD Signature;    /* Format signature */
  450.     DWORD Version;      /* Format version number */
  451.     DWORD Data;         /* Size of data in bytes */
  452.     DWORD OffsetToData; /* Offset to data */
  453. } EMRFORMAT;
  454.  
  455. typedef struct _GdiCommentMultiFormats
  456. {
  457.     DWORD Identifier;       /* Comment ID (0x43494447) */
  458.     DWORD Comment;          /* Multiformats ID (0x40000004) */
  459.     LONG  BoundsLeft;       /* Left side of bounding rectangle */
  460.     LONG  BoundsRight;      /* Right side of bounding rectangle */
  461.     LONG  BoundsTop;        /* Top side of bounding rectangle */
  462.     LONG  BoundsBottom;     /* Bottom side of bounding rectangle */
  463.     DWORD NumFormats;       /* Number of formats in comment */
  464. #if DOCUMENTATION_ONLY_ILLEGAL_C
  465.     EMRFORMAT Data[];       /* Array of comment data */
  466. #endif
  467. } GDICOMMENTMULTIFORMATS;
  468.  
  469. /* Binary raster ops */
  470. #define R2_BLACK            1
  471. #define R2_NOTMERGEPEN      2
  472. #define R2_MASKNOTPEN       3
  473. #define R2_NOTCOPYPEN       4
  474. #define R2_MASKPENNOT       5
  475. #define R2_NOT              6
  476. #define R2_XORPEN           7
  477. #define R2_NOTMASKPEN       8
  478. #define R2_MASKPEN          9
  479. #define R2_NOTXORPEN       10
  480. #define R2_NOP             11
  481. #define R2_MERGENOTPEN     12
  482. #define R2_COPYPEN         13
  483. #define R2_MERGEPENNOT     14
  484. #define R2_MERGEPEN        15
  485. #define R2_WHITE           16
  486.  
  487. /* Background mix modes */
  488. #define TRANSPARENT        1
  489. #define OPAQUE            2
  490.  
  491. /* Brush styles */
  492. #define BS_SOLID            0
  493. #define BS_NULL             1
  494. #define BS_HATCHED          2
  495. #define BS_PATTERN          3
  496. #define BS_DIBPATTERN       5
  497. #define BS_DIBPATTERNPT     6
  498. #define BS_PATTERN8X8       7
  499. #define BS_DIBPATTERN8X8    8
  500. #define BS_MONOPATTERN      9
  501.  
  502. /* Pen styles */
  503. #define PS_SOLID            0
  504. #define PS_DASH             1
  505. #define PS_DOT              2
  506. #define PS_DASHDOT          3
  507. #define PS_DASHDOTDOT       4
  508. #define PS_NULL             5
  509. #define PS_INSIDEFRAME      6
  510.  
  511. /* Polygon fill modes */
  512. #define ALTERNATE        1
  513. #define WINDING            2
  514.  
  515. /* Modes for SetMapMode */
  516. #define MM_TEXT             1
  517. #define MM_LOMETRIC         2
  518. #define MM_HIMETRIC         3
  519. #define MM_LOENGLISH        4
  520. #define MM_HIENGLISH        5
  521. #define MM_TWIPS            6
  522. #define MM_ISOTROPIC        7
  523. #define MM_ANISOTROPIC      8
  524.  
  525.  
  526. #define ReadOK(file,buffer,len) (fread(buffer, len, 1, file) != 0)
  527.  
  528. #define NPARMWORDS 16
  529.  
  530. #ifndef G_BYTE_ORDER        /* Development glib has byte sex stuff,
  531.                  * but if we're on 1.0, use something else
  532.                  */
  533.  
  534. #define G_LITTLE_ENDIAN 1234
  535. #define G_BIG_ENDIAN    4321
  536.  
  537. #if defined(__i386__)
  538. #define G_BYTE_ORDER G_LITTLE_ENDIAN
  539. #elif defined(__hppa) || defined(__sparc)
  540. #define G_BYTE_ORDER G_BIG_ENDIAN
  541. #else
  542. #error set byte order by hand by adding your machine above
  543. #endif
  544.  
  545. /* This is straight from the newest glib.h */
  546.  
  547. /* Basic bit swapping functions
  548.  */
  549. #define GUINT16_SWAP_LE_BE_CONSTANT(val)    ((guint16) ( \
  550.     (((guint16) (val) & (guint16) 0x00ffU) << 8) | \
  551.     (((guint16) (val) & (guint16) 0xff00U) >> 8)))
  552. #define GUINT32_SWAP_LE_BE_CONSTANT(val)    ((guint32) ( \
  553.     (((guint32) (val) & (guint32) 0x000000ffU) << 24) | \
  554.     (((guint32) (val) & (guint32) 0x0000ff00U) <<  8) | \
  555.     (((guint32) (val) & (guint32) 0x00ff0000U) >>  8) | \
  556.     (((guint32) (val) & (guint32) 0xff000000U) >> 24)))
  557.  
  558. /* Intel specific stuff for speed
  559.  */
  560. #if defined (__i386__) && (defined __GNUC__)
  561.  
  562. #  define GUINT16_SWAP_LE_BE_X86(val) \
  563.      (__extension__                        \
  564.       ({ register guint16 __v;                    \
  565.      if (__builtin_constant_p (val))            \
  566.        __v = GUINT16_SWAP_LE_BE_CONSTANT (val);        \
  567.      else                            \
  568.        __asm__ __volatile__ ("rorw $8, %w0"            \
  569.                  : "=r" (__v)            \
  570.                  : "0" ((guint16) (val))    \
  571.                  : "cc");            \
  572.     __v; }))
  573.  
  574. #  define GUINT16_SWAP_LE_BE(val) \
  575.      ((guint16) GUINT16_SWAP_LE_BE_X86 ((guint16) (val)))
  576.  
  577. #  if !defined(__i486__) && !defined(__i586__) \
  578.       && !defined(__pentium__) && !defined(__pentiumpro__) && !defined(__i686__)
  579. #     define GUINT32_SWAP_LE_BE_X86(val) \
  580.         (__extension__                        \
  581.          ({ register guint32 __v;                \
  582.         if (__builtin_constant_p (val))            \
  583.           __v = GUINT32_SWAP_LE_BE_CONSTANT (val);        \
  584.       else                            \
  585.         __asm__ __volatile__ ("rorw $8, %w0\n\t"        \
  586.                   "rorl $16, %0\n\t"        \
  587.                   "rorw $8, %w0"        \
  588.                   : "=r" (__v)            \
  589.                   : "0" ((guint32) (val))    \
  590.                   : "cc");            \
  591.     __v; }))
  592.  
  593. #  else /* 486 and higher has bswap */
  594. #     define GUINT32_SWAP_LE_BE_X86(val) \
  595.         (__extension__                        \
  596.          ({ register guint32 __v;                \
  597.         if (__builtin_constant_p (val))            \
  598.           __v = GUINT32_SWAP_LE_BE_CONSTANT (val);        \
  599.       else                            \
  600.         __asm__ __volatile__ ("bswap %0"            \
  601.                   : "=r" (__v)            \
  602.                   : "0" ((guint32) (val)));    \
  603.     __v; }))
  604. #  endif /* processor specific 32-bit stuff */
  605.  
  606. #  define GUINT32_SWAP_LE_BE(val) \
  607.      ((guint32) GUINT32_SWAP_LE_BE_X86 ((guint32) (val)))
  608.  
  609. #else /* !__i386__ */
  610. #  define GUINT16_SWAP_LE_BE(val) (GUINT16_SWAP_LE_BE_CONSTANT (val))
  611. #  define GUINT32_SWAP_LE_BE(val) (GUINT32_SWAP_LE_BE_CONSTANT (val))
  612. #endif /* __i386__ */
  613.  
  614. #ifdef HAVE_GINT64
  615. #define GUINT64_SWAP_LE_BE(val)         ((guint64) ( \
  616.     (((guint64) (val) & (guint64) 0x00000000000000ffU) << 56) | \
  617.     (((guint64) (val) & (guint64) 0x000000000000ff00U) << 40) | \
  618.     (((guint64) (val) & (guint64) 0x0000000000ff0000U) << 24) | \
  619.     (((guint64) (val) & (guint64) 0x00000000ff000000U) <<  8) | \
  620.     (((guint64) (val) & (guint64) 0x000000ff00000000U) >>  8) | \
  621.     (((guint64) (val) & (guint64) 0x0000ff0000000000U) >> 24) | \
  622.     (((guint64) (val) & (guint64) 0x00ff000000000000U) >> 40) | \
  623.     (((guint64) (val) & (guint64) 0xff00000000000000U) >> 56)))
  624. #endif
  625.  
  626. #define GUINT16_SWAP_LE_PDP(val)    ((guint16) (val))
  627. #define GUINT16_SWAP_BE_PDP(val)    (GUINT16_SWAP_LE_BE (val))
  628. #define GUINT32_SWAP_LE_PDP(val)    ((guint32) ( \
  629.     (((guint32) (val) & (guint32) 0x0000ffffU) << 16) | \
  630.     (((guint32) (val) & (guint32) 0xffff0000U) >> 16)))
  631. #define GUINT32_SWAP_BE_PDP(val)    ((guint32) ( \
  632.     (((guint32) (val) & (guint32) 0x00ff00ffU) << 8) | \
  633.     (((guint32) (val) & (guint32) 0xff00ff00U) >> 8)))
  634.  
  635. #if G_BYTE_ORDER == G_LITTLE_ENDIAN
  636. #  define GINT16_TO_LE(val)        ((gint16) (val))
  637. #  define GUINT16_TO_LE(val)        ((guint16) (val))
  638. #  define GINT16_TO_BE(val)        ((gint16) GUINT16_SWAP_LE_BE (val))
  639. #  define GUINT16_TO_BE(val)        (GUINT16_SWAP_LE_BE (val))
  640. #  define GINT16_FROM_LE(val)        ((gint16) (val))
  641. #  define GUINT16_FROM_LE(val)        ((guint16) (val))
  642. #  define GINT16_FROM_BE(val)        ((gint16) GUINT16_SWAP_LE_BE (val))
  643. #  define GUINT16_FROM_BE(val)        (GUINT16_SWAP_LE_BE (val))
  644. #  define GINT32_TO_LE(val)        ((gint32) (val))
  645. #  define GUINT32_TO_LE(val)        ((guint32) (val))
  646. #  define GINT32_TO_BE(val)        ((gint32) GUINT32_SWAP_LE_BE (val))
  647. #  define GUINT32_TO_BE(val)        (GUINT32_SWAP_LE_BE (val))
  648. #  define GINT32_FROM_LE(val)        ((gint32) (val))
  649. #  define GUINT32_FROM_LE(val)        ((guint32) (val))
  650. #  define GINT32_FROM_BE(val)        ((gint32) GUINT32_SWAP_LE_BE (val))
  651. #  define GUINT32_FROM_BE(val)        (GUINT32_SWAP_LE_BE (val))
  652. #  ifdef HAVE_GINT64
  653. #  define GINT64_TO_LE(val)        ((gint64) (val))
  654. #  define GUINT64_TO_LE(val)        ((guint64) (val))
  655. #  define GINT64_TO_BE(val)        ((gint64) GUINT64_SWAP_LE_BE (val))
  656. #  define GUINT64_TO_BE(val)        (GUINT64_SWAP_LE_BE (val))
  657. #  define GINT64_FROM_LE(val)        ((gint64) (val))
  658. #  define GUINT64_FROM_LE(val)        ((guint64) (val))
  659. #  define GINT64_FROM_BE(val)        ((gint64) GUINT64_SWAP_LE_BE (val))
  660. #  define GUINT64_FROM_BE(val)        (GUINT64_SWAP_LE_BE (val))
  661. #  endif
  662. #elif G_BYTE_ORDER == G_BIG_ENDIAN
  663. #  define GINT16_TO_BE(val)        ((gint16) (val))
  664. #  define GUINT16_TO_BE(val)        ((guint16) (val))
  665. #  define GINT16_TO_LE(val)        ((gint16) GUINT16_SWAP_LE_BE (val))
  666. #  define GUINT16_TO_LE(val)        (GUINT16_SWAP_LE_BE (val))
  667. #  define GINT16_FROM_BE(val)        ((gint16) (val))
  668. #  define GUINT16_FROM_BE(val)        ((guint16) (val))
  669. #  define GINT16_FROM_LE(val)        ((gint16) GUINT16_SWAP_LE_BE (val))
  670. #  define GUINT16_FROM_LE(val)        (GUINT16_SWAP_LE_BE (val))
  671. #  define GINT32_TO_BE(val)        ((gint32) (val))
  672. #  define GUINT32_TO_BE(val)        ((guint32) (val))
  673. #  define GINT32_TO_LE(val)        ((gint32) GUINT32_SWAP_LE_BE (val))
  674. #  define GUINT32_TO_LE(val)        (GUINT32_SWAP_LE_BE (val))
  675. #  define GINT32_FROM_BE(val)        ((gint32) (val))
  676. #  define GUINT32_FROM_BE(val)        ((guint32) (val))
  677. #  define GINT32_FROM_LE(val)        ((gint32) GUINT32_SWAP_LE_BE (val))
  678. #  define GUINT32_FROM_LE(val)        (GUINT32_SWAP_LE_BE (val))
  679. #  ifdef HAVE_GINT64
  680. #  define GINT64_TO_BE(val)        ((gint64) (val))
  681. #  define GUINT64_TO_BE(val)        ((guint64) (val))
  682. #  define GINT64_TO_LE(val)        ((gint64) GUINT64_SWAP_LE_BE (val))
  683. #  define GUINT64_TO_LE(val)        (GUINT64_SWAP_LE_BE (val))
  684. #  define GINT64_FROM_BE(val)        ((gint64) (val))
  685. #  define GUINT64_FROM_BE(val)        ((guint64) (val))
  686. #  define GINT64_FROM_LE(val)        ((gint64) GUINT64_SWAP_LE_BE (val))
  687. #  define GUINT64_FROM_LE(val)        (GUINT64_SWAP_LE_BE (val))
  688. #  endif
  689. #else
  690. /* PDP stuff not implemented */
  691. #endif
  692.  
  693. #if (SIZEOF_LONG == 8)
  694. #  define GLONG_TO_LE(val)        ((glong) GINT64_TO_LE (val))
  695. #  define GULONG_TO_LE(val)        ((gulong) GUINT64_TO_LE (val))
  696. #  define GLONG_TO_BE(val)        ((glong) GINT64_TO_BE (val))
  697. #  define GULONG_TO_BE(val)        ((gulong) GUINT64_TO_BE (val))
  698. #  define GLONG_FROM_LE(val)        ((glong) GINT64_FROM_LE (val))
  699. #  define GULONG_FROM_LE(val)        ((gulong) GUINT64_FROM_LE (val))
  700. #  define GLONG_FROM_BE(val)        ((glong) GINT64_FROM_BE (val))
  701. #  define GULONG_FROM_BE(val)        ((gulong) GUINT64_FROM_BE (val))
  702. #elif (SIZEOF_LONG == 4)
  703. #  define GLONG_TO_LE(val)        ((glong) GINT32_TO_LE (val))
  704. #  define GULONG_TO_LE(val)        ((gulong) GUINT32_TO_LE (val))
  705. #  define GLONG_TO_BE(val)        ((glong) GINT32_TO_BE (val))
  706. #  define GULONG_TO_BE(val)        ((gulong) GUINT32_TO_BE (val))
  707. #  define GLONG_FROM_LE(val)        ((glong) GINT32_FROM_LE (val))
  708. #  define GULONG_FROM_LE(val)        ((gulong) GUINT32_FROM_LE (val))
  709. #  define GLONG_FROM_BE(val)        ((glong) GINT32_FROM_BE (val))
  710. #  define GULONG_FROM_BE(val)        ((gulong) GUINT32_FROM_BE (val))
  711. #endif
  712.  
  713. #if (SIZEOF_INT == 8)
  714. #  define GINT_TO_LE(val)        ((gint) GINT64_TO_LE (val))
  715. #  define GUINT_TO_LE(val)        ((guint) GUINT64_TO_LE (val))
  716. #  define GINT_TO_BE(val)        ((gint) GINT64_TO_BE (val))
  717. #  define GUINT_TO_BE(val)        ((guint) GUINT64_TO_BE (val))
  718. #  define GINT_FROM_LE(val)        ((gint) GINT64_FROM_LE (val))
  719. #  define GUINT_FROM_LE(val)        ((guint) GUINT64_FROM_LE (val))
  720. #  define GINT_FROM_BE(val)        ((gint) GINT64_FROM_BE (val))
  721. #  define GUINT_FROM_BE(val)        ((guint) GUINT64_FROM_BE (val))
  722. #elif (SIZEOF_INT == 4)
  723. #  define GINT_TO_LE(val)        ((gint) GINT32_TO_LE (val))
  724. #  define GUINT_TO_LE(val)        ((guint) GUINT32_TO_LE (val))
  725. #  define GINT_TO_BE(val)        ((gint) GINT32_TO_BE (val))
  726. #  define GUINT_TO_BE(val)        ((guint) GUINT32_TO_BE (val))
  727. #  define GINT_FROM_LE(val)        ((gint) GINT32_FROM_LE (val))
  728. #  define GUINT_FROM_LE(val)        ((guint) GUINT32_FROM_LE (val))
  729. #  define GINT_FROM_BE(val)        ((gint) GINT32_FROM_BE (val))
  730. #  define GUINT_FROM_BE(val)        ((guint) GUINT32_FROM_BE (val))
  731. #elif (SIZEOF_INT == 2)
  732. #  define GINT_TO_LE(val)        ((gint) GINT16_TO_LE (val))
  733. #  define GUINT_TO_LE(val)        ((guint) GUINT16_TO_LE (val))
  734. #  define GINT_TO_BE(val)        ((gint) GINT16_TO_BE (val))
  735. #  define GUINT_TO_BE(val)        ((guint) GUINT16_TO_BE (val))
  736. #  define GINT_FROM_LE(val)        ((gint) GINT16_FROM_LE (val))
  737. #  define GUINT_FROM_LE(val)        ((guint) GUINT16_FROM_LE (val))
  738. #  define GINT_FROM_BE(val)        ((gint) GINT16_FROM_BE (val))
  739. #  define GUINT_FROM_BE(val)        ((guint) GUINT16_FROM_BE (val))
  740. #endif
  741.  
  742. #endif
  743.  
  744. typedef struct
  745. {
  746.   double scale;
  747. } WMFLoadVals;
  748.  
  749. static WMFLoadVals load_vals =
  750. {
  751.   1.0                /* scale */
  752. };
  753.  
  754. typedef struct
  755. {
  756.   gint run;
  757. } WMFLoadInterface;
  758.  
  759. static WMFLoadInterface load_interface =
  760. {
  761.   FALSE
  762. };
  763.  
  764. typedef struct
  765. {
  766.   GtkWidget *dialog;
  767.   GtkAdjustment *scale;
  768. } LoadDialogVals;
  769.  
  770. typedef enum
  771. {
  772.   OBJ_BITMAP,
  773.   OBJ_BRUSH,
  774.   OBJ_PATTERNBRUSH,
  775.   OBJ_FONT,
  776.   OBJ_PEN,
  777.   OBJ_REGION,
  778.   OBJ_PALETTE
  779. } ObjectType;
  780.  
  781. typedef struct
  782. {
  783.   int dummy;
  784. } BitmapObject;
  785.  
  786. typedef struct
  787. {
  788.   GdkColor color;
  789.   gboolean invisible;
  790.   guint style;
  791.   glong hatch;
  792. } BrushObject;
  793.  
  794. typedef struct
  795. {
  796.   int dummy;
  797. } PatternBrushObject;
  798.  
  799. typedef struct
  800. {
  801.   GdkColor color;
  802.   gboolean invisible;
  803.   gushort width;
  804.   GdkLineStyle style;
  805. } PenObject;
  806.  
  807. typedef struct
  808. {
  809.   GdkFont *font;
  810. } FontObject;
  811.  
  812. typedef struct
  813. {
  814.   int dummy;
  815. } PaletteObject;
  816.  
  817. typedef struct
  818. {
  819.   ObjectType type;
  820.   union
  821.   {
  822.     BitmapObject bitmap;
  823.     BrushObject brush;
  824.     PatternBrushObject pbrush;
  825.     PenObject pen;
  826.     FontObject font;
  827.     PaletteObject palette;
  828.   } u;
  829. } Object;
  830.  
  831. typedef struct
  832. {
  833.   GdkGC *gc;
  834.   GdkColor bg;
  835.   BrushObject *brush;
  836.   PenObject *pen;
  837.   FontObject *font;
  838.   GdkColor textColor;
  839.   gint tag;
  840. } DC;
  841.  
  842. static gint saved_dc_tag = 1;
  843.  
  844. typedef struct
  845. {
  846.   GdkPixmap *pixmap;
  847.   DC dc;
  848.   GSList *dc_stack;
  849.   GdkColormap *colormap;
  850.   guint width, height;
  851.   double scalex, scaley;
  852.   double curx, cury;
  853. } Canvas;
  854.  
  855. typedef struct
  856. {
  857.   gboolean valid;
  858.   gint org_x, org_y;
  859.   gint ext_x, ext_y;
  860. } OrgAndExt;
  861.  
  862. static void   query      (void);
  863. static void   run        (char    *name,
  864.                           int      nparams,
  865.                           GParam  *param,
  866.                           int     *nreturn_vals,
  867.                           GParam **return_vals);
  868. static gint32 load_image (char   *filename);
  869.  
  870. static gint readparams (DWORD size,
  871.             guint nparams,
  872.             FILE *fd,
  873.             WORD *params);
  874.  
  875. static void sync_record (DWORD size,
  876.              guint nparams,
  877.              FILE *fd);
  878.  
  879. GPlugInInfo PLUG_IN_INFO =
  880. {
  881.   NULL,    /* init_proc */
  882.   NULL,    /* quit_proc */
  883.   query,   /* query_proc */
  884.   run,     /* run_proc */
  885. };
  886.  
  887. static GRunModeType l_run_mode;
  888.  
  889. static int pixs_per_in;
  890.  
  891. static void
  892. load_close_callback (GtkWidget *widget,
  893.                      gpointer   data)
  894.  
  895. {
  896.   gtk_main_quit ();
  897. }
  898.  
  899. static void
  900. load_ok_callback (GtkWidget *widget,
  901.                   gpointer   data)
  902.  
  903. {
  904.   LoadDialogVals *vals = (LoadDialogVals *)data;
  905.  
  906.   /* Read scale */
  907.   load_vals.scale = pow (2.0, vals->scale->value);
  908.  
  909.   load_interface.run = TRUE;
  910.   gtk_widget_destroy (GTK_WIDGET (vals->dialog));
  911. }
  912.  
  913. static gint
  914. load_dialog (void)
  915. {
  916.   LoadDialogVals *vals;
  917.   GtkWidget *frame;
  918.   GtkWidget *button;
  919.   GtkWidget *vbox;
  920.   GtkWidget *hbox;
  921.   GtkWidget *label;
  922.   GtkWidget *table;
  923.   GtkWidget *slider;
  924.  
  925.   gchar **argv;
  926.   gint argc;
  927.  
  928.   argc = 1;
  929.   argv = g_new (gchar *, 1);
  930.   argv[0] = g_strdup ("load");
  931.  
  932.   gtk_init (&argc, &argv);
  933.   gtk_rc_parse (gimp_gtkrc ());
  934.  
  935.   vals = g_malloc (sizeof (LoadDialogVals));
  936.   
  937.   vals->dialog = gtk_dialog_new ();
  938.  
  939.   gtk_window_set_title (GTK_WINDOW (vals->dialog), "Load Windows Metafile");
  940.   gtk_window_position (GTK_WINDOW (vals->dialog), GTK_WIN_POS_MOUSE);
  941.   gtk_signal_connect (GTK_OBJECT (vals->dialog), "destroy",
  942.                       (GtkSignalFunc) load_close_callback,
  943.                       NULL);
  944.  
  945.   /*  Action area  */
  946.   button = gtk_button_new_with_label ("OK");
  947.   GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT);
  948.   gtk_signal_connect (GTK_OBJECT (button), "clicked",
  949.                       (GtkSignalFunc) load_ok_callback,
  950.                       vals);
  951.   gtk_box_pack_start (GTK_BOX (GTK_DIALOG (vals->dialog)->action_area), button,
  952.                       TRUE, TRUE, 0);
  953.   gtk_widget_grab_default (button);
  954.   gtk_widget_show (button);
  955.  
  956.   button = gtk_button_new_with_label ("Cancel");
  957.   GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT);
  958.   gtk_signal_connect_object (GTK_OBJECT (button), "clicked",
  959.                              (GtkSignalFunc) gtk_widget_destroy,
  960.                              GTK_OBJECT (vals->dialog));
  961.   gtk_box_pack_start (GTK_BOX (GTK_DIALOG (vals->dialog)->action_area), button,
  962.                       TRUE, TRUE, 0);
  963.   gtk_widget_show (button);
  964.  
  965.   hbox = gtk_hbox_new (FALSE, 0);
  966.   gtk_container_border_width (GTK_CONTAINER (hbox), 0);
  967.   gtk_box_pack_start (GTK_BOX (GTK_DIALOG (vals->dialog)->vbox), hbox,
  968.                       TRUE, TRUE, 0);
  969.   gtk_widget_show (hbox);
  970.  
  971.   /* Rendering */
  972.   frame = gtk_frame_new ("Rendering");
  973.   gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_ETCHED_IN);
  974.   gtk_container_border_width (GTK_CONTAINER (frame), 10);
  975.   gtk_box_pack_start (GTK_BOX (hbox), frame, TRUE, TRUE, 0);
  976.   vbox = gtk_vbox_new (FALSE, 5);
  977.   gtk_container_border_width (GTK_CONTAINER (vbox), 5);
  978.   gtk_container_add (GTK_CONTAINER (frame), vbox);
  979.  
  980.   /* Scale label */
  981.   table = gtk_table_new (1, 2, FALSE);
  982.   gtk_table_set_row_spacings (GTK_TABLE (table), 5);
  983.   gtk_table_set_col_spacings (GTK_TABLE (table), 5);
  984.   gtk_box_pack_start (GTK_BOX (vbox), table, TRUE, TRUE, 0);
  985.   gtk_widget_show (table);
  986.  
  987.   label = gtk_label_new ("Scale (log 2)");
  988.   gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
  989.   gtk_table_attach (GTK_TABLE (table), label, 0, 1, 0, 1,
  990.             GTK_FILL, GTK_FILL, 0, 0);
  991.   gtk_widget_show (label);
  992.  
  993.   /* Scale slider */
  994.   vals->scale = GTK_ADJUSTMENT (gtk_adjustment_new (0.0, -2.0, 2.0, 0.2, 0.2, 0.0));
  995.   slider = gtk_hscale_new (vals->scale);
  996.   gtk_table_attach (GTK_TABLE (table), slider, 1, 2, 0, 1,
  997.             GTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL, 0, 0);
  998.   gtk_scale_set_value_pos (GTK_SCALE (slider), GTK_POS_TOP);
  999.   gtk_range_set_update_policy (GTK_RANGE (slider), GTK_UPDATE_DELAYED);
  1000.   gtk_widget_show (slider);
  1001.  
  1002.   gtk_widget_show (vbox);
  1003.   gtk_widget_show (frame);
  1004.  
  1005.   gtk_widget_show (vals->dialog);
  1006.  
  1007.   gtk_main ();
  1008.   gdk_flush ();
  1009.  
  1010.   g_free (vals);
  1011.  
  1012.   return load_interface.run;
  1013. }
  1014.  
  1015. static void
  1016. check_load_vals (void)
  1017. {
  1018.   if (load_vals.scale < 0.01)
  1019.     load_vals.scale = 0.01;
  1020.   else if (load_vals.scale > 100.)
  1021.     load_vals.scale = 100.;
  1022. }
  1023.  
  1024. MAIN ()
  1025.  
  1026. static void
  1027. query ()
  1028. {
  1029.   static GParamDef load_args[] =
  1030.   {
  1031.     { PARAM_INT32, "run_mode", "Interactive, non-interactive" },
  1032.     { PARAM_STRING, "filename", "The name of the file to load" },
  1033.     { PARAM_STRING, "raw_filename", "The name entered" },
  1034.   };
  1035.   static int nload_args = sizeof (load_args) / sizeof (load_args[0]);
  1036.   static GParamDef load_return_vals[] =
  1037.   {
  1038.     { PARAM_IMAGE, "image", "Output image" },
  1039.   };
  1040.   static int nload_return_vals = sizeof (load_return_vals) / sizeof (load_return_vals[0]);
  1041.   static GParamDef load_setargs_args[] =
  1042.   {
  1043.     { PARAM_FLOAT, "scale", "Scale in which to load image" }
  1044.   };
  1045.   static int nload_setargs_args = sizeof (load_setargs_args) / sizeof (load_setargs_args[0]);
  1046.  
  1047.   gimp_install_procedure ("file_wmf_load",
  1048.                           "loads files of the Windows(tm) metafile file format",
  1049.                           "FIXME: write help for file_wmf_load",
  1050.                           "Tor Lillqvist <tml@iki.fi>",
  1051.                           "Tor Lillqvist",
  1052.                           "1998",
  1053.                           "<Load>/WMF",
  1054.               NULL,
  1055.                           PROC_PLUG_IN,
  1056.                           nload_args, nload_return_vals,
  1057.                           load_args, load_return_vals);
  1058.  
  1059.   gimp_install_procedure ("file_wmf_load_setargs",
  1060.               "set additional parameters for the procedure file_wmf_load",
  1061.               "set additional parameters for the procedure file_wmf_load",
  1062.               "Tor Lillqvist <tml@iki.fi>",
  1063.                           "Tor Lillqvist",
  1064.                           "1998",
  1065.               NULL,
  1066.               NULL,
  1067.               PROC_PLUG_IN,
  1068.               nload_setargs_args, 0,
  1069.               load_setargs_args, NULL);
  1070.   
  1071.   gimp_register_magic_load_handler ("file_wmf_load", "wmf,apm", "", "0,string,\\327\\315\\306\\232");
  1072. }
  1073.  
  1074. static void
  1075. run (char    *name,
  1076.      int      nparams,
  1077.      GParam  *param,
  1078.      int     *nreturn_vals,
  1079.      GParam **return_vals)
  1080. {
  1081.   static GParam values[2];
  1082.   gint32 image_ID;
  1083.  
  1084.   l_run_mode = param[0].data.d_int32;
  1085.  
  1086.   *nreturn_vals = 1;
  1087.   *return_vals = values;
  1088.   values[0].type = PARAM_STATUS;
  1089.   values[0].data.d_status = STATUS_CALLING_ERROR;
  1090.  
  1091.   if (strcmp (name, "file_wmf_load") == 0)
  1092.     {
  1093.       switch (l_run_mode)
  1094.     {
  1095.     case RUN_INTERACTIVE:
  1096.       gimp_get_data ("file_wmf_load", &load_vals);
  1097.  
  1098.       if (!load_dialog ())
  1099.         return;
  1100.       break;
  1101.       
  1102.     case RUN_NONINTERACTIVE:
  1103.       gimp_get_data ("file_wmf_load", &load_vals);
  1104.       break;
  1105.  
  1106.     case RUN_WITH_LAST_VALS:
  1107.       gimp_get_data ("file_wmf_load", &load_vals);
  1108.  
  1109.     }
  1110.  
  1111.       check_load_vals ();
  1112.       
  1113.       image_ID = load_image (param[1].data.d_string);
  1114.       
  1115.       values[0].data.d_status = (image_ID != -1) ? STATUS_SUCCESS : STATUS_EXECUTION_ERROR;
  1116.       
  1117.       if (values[0].data.d_status == STATUS_SUCCESS)
  1118.     {
  1119.       gimp_set_data ("file_wmf_load", &load_vals, sizeof (load_vals));
  1120.       *nreturn_vals = 2;
  1121.       values[1].type = PARAM_IMAGE;
  1122.       values[1].data.d_image = image_ID;
  1123.     }
  1124.       else
  1125.     {
  1126.       values[0].data.d_status = STATUS_EXECUTION_ERROR;
  1127.     }
  1128.     }
  1129. }
  1130.  
  1131. static Object *
  1132. new_object (ObjectType type,
  1133.         Object **objects,
  1134.         const int nobjects)
  1135. {
  1136.   gint i;
  1137.   Object *result = NULL;
  1138.  
  1139.   for (i = 0; i < nobjects; i++)
  1140.     if (objects[i] == NULL)
  1141.       {
  1142.     objects[i] = result = g_new (Object, 1);
  1143.     result->type = type;
  1144.     break;
  1145.       }
  1146.   if (i == nobjects)
  1147.     g_message ("WMF: Creating too many objects");
  1148.  
  1149.   return result;
  1150. }
  1151.  
  1152. static Canvas *
  1153. make_canvas (OrgAndExt *window,
  1154.          OrgAndExt *viewport,
  1155.          gboolean have_bbox,
  1156.          GdkRectangle *bbox,
  1157.          guint units_per_in)
  1158. {
  1159.   Canvas *canvas = g_new (Canvas, 1);
  1160.  
  1161.   if (!window->valid)
  1162.     {
  1163.       if (have_bbox)
  1164.     {
  1165.       window->org_x = bbox->x;
  1166.       window->ext_x = bbox->width;
  1167.       window->org_y = bbox->y;
  1168.       window->ext_y = bbox->height;
  1169.     }
  1170.       else
  1171.     {
  1172.       window->org_x = window->org_y = 0;
  1173.       /* Just pick a size. */
  1174.       window->ext_x = units_per_in * 4;
  1175.       window->ext_y = units_per_in * 3;
  1176.     }
  1177.       window->valid = TRUE;
  1178.     }
  1179.  
  1180.   canvas->scalex = canvas->scaley = load_vals.scale;
  1181.   
  1182.   if (!viewport->valid)
  1183.     {
  1184.       viewport->org_x = viewport->org_y = 0;
  1185.       viewport->ext_x = canvas->scalex * fabs (window->ext_x) / units_per_in * pixs_per_in;
  1186.       viewport->ext_y = canvas->scaley * fabs (window->ext_y) / units_per_in * pixs_per_in;
  1187.       viewport->valid = TRUE;
  1188.     }
  1189. #if 0
  1190.   g_print ("window: (%d,%d)--(%d,%d), viewport: (%d,%d)--(%d,%d)\n",
  1191.        window->org_x, window->org_y, window->org_x + window->ext_x, window->org_y + window->ext_y, 
  1192.        viewport->org_x, viewport->org_y, viewport->org_x + viewport->ext_x, viewport->org_y + viewport->ext_y);
  1193. #endif
  1194.  
  1195.   canvas->colormap = gdk_colormap_get_system ();
  1196.  
  1197.   canvas->width = viewport->ext_x;
  1198.   canvas->height = viewport->ext_y;
  1199.  
  1200.   canvas->pixmap = gdk_pixmap_new (NULL, viewport->ext_x, viewport->ext_y,
  1201.                    gdk_visual_get_system ()->depth);
  1202.  
  1203.   canvas->dc.gc = gdk_gc_new (canvas->pixmap);
  1204.  
  1205.   canvas->dc.bg.red =
  1206.     canvas->dc.bg.green =
  1207.     canvas->dc.bg.blue = 0xFFFF;
  1208.   gdk_color_alloc (canvas->colormap, &canvas->dc.bg);
  1209.  
  1210.   canvas->dc.brush = g_new (BrushObject, 1);
  1211.   canvas->dc.brush->invisible = FALSE;
  1212.   canvas->dc.brush->color.red =
  1213.     canvas->dc.brush->color.green =
  1214.     canvas->dc.brush->color.blue = 0xFFFF;
  1215.   gdk_color_alloc (canvas->colormap, &canvas->dc.brush->color);
  1216.  
  1217.   canvas->dc.pen = g_new (PenObject, 1);
  1218.   canvas->dc.pen->invisible = FALSE;
  1219.   canvas->dc.pen->color.red =
  1220.     canvas->dc.pen->color.green =
  1221.     canvas->dc.pen->color.blue = 0;
  1222.   gdk_color_alloc (canvas->colormap, &canvas->dc.pen->color);
  1223.  
  1224.   canvas->dc.font = g_new (FontObject, 1);
  1225.   canvas->dc.font->font = gdk_font_load ("-adobe-helvetica-medium-r-normal--*-120-*-*-*-*-*-*");
  1226.  
  1227.   canvas->dc.textColor.red =
  1228.     canvas->dc.textColor.green =
  1229.     canvas->dc.textColor.blue = 0;
  1230.   gdk_color_alloc (canvas->colormap, &canvas->dc.textColor);
  1231.  
  1232.   canvas->dc_stack = g_slist_alloc ();
  1233.  
  1234.   gdk_gc_set_foreground (canvas->dc.gc, &canvas->dc.brush->color);
  1235.   gdk_draw_rectangle (canvas->pixmap, canvas->dc.gc, TRUE, 0, 0,
  1236.               viewport->ext_x, viewport->ext_y);
  1237.  
  1238.   canvas->curx = canvas->cury = 0.0;
  1239.  
  1240.   return canvas;
  1241. }
  1242.  
  1243. static void
  1244. set_color (WORD *params,
  1245.        GdkColor *color)
  1246. {
  1247.   color->red = ((GUINT16_FROM_LE (params[0]) & 0x00FF) * 65535) / 255;
  1248.   color->green = (((GUINT16_FROM_LE (params[0]) & 0xFF00) >> 8) * 65535) / 255;
  1249.   color->blue = ((GUINT16_FROM_LE (params[1]) & 0x00FF) * 65535) / 255;
  1250. }
  1251.  
  1252. static gint32
  1253. load_image (char *filename)
  1254. {
  1255.   FILE *fp;
  1256.   char *name_buf;
  1257.   guchar buffer[100];
  1258.   gboolean warned_unhandled = FALSE;
  1259.   gboolean warned_opaque = FALSE;
  1260.   gboolean warned_orientation = FALSE;
  1261.   WMFHEAD wmf_head;
  1262.   PLACEABLEMETAHEADER apm_head;
  1263.   WMFRECORD record;
  1264.   WORD params[NPARMWORDS];
  1265.   Object **objects, *objp = NULL;
  1266.   guint nobjects;
  1267.   guint units_per_in;
  1268.  
  1269.   guint i, j, jj, k;
  1270.   gint ix;
  1271.   guchar *string;
  1272.   guint record_counter = 0;
  1273.   GdkRectangle bbox;
  1274.   gboolean have_bbox = FALSE;
  1275.   OrgAndExt window, viewport;
  1276.  
  1277. #define XMAPPAR(param) (((double) (GINT16_FROM_LE (param) - window.org_x) * viewport.ext_x / window.ext_x) + viewport.org_x)
  1278. #define YMAPPAR(param) (((double) (GINT16_FROM_LE (param) - window.org_y) * viewport.ext_y / window.ext_y) + viewport.org_y)
  1279.  
  1280. #define XIMAPPAR(param) ((gint) XMAPPAR (param))
  1281. #define YIMAPPAR(param) ((gint) YMAPPAR (param))
  1282.  
  1283. #define XSCALE(value) ((value) * (double) viewport.ext_x / window.ext_x)
  1284. #define YSCALE(value) ((value) * (double) viewport.ext_y / window.ext_y)
  1285.  
  1286.   Canvas *canvas = NULL;
  1287.   GdkGCValues gc_values;
  1288.   DC *dc;
  1289.   GdkVisual *visual;
  1290.   GdkPoint *points;
  1291.   double x, y;
  1292.   guint npoints;
  1293.   guint npolys;
  1294.   guint *nppoints;
  1295.   GdkImage *image;
  1296.  
  1297.   GPixelRgn pixel_rgn;
  1298.   gint32 image_ID = -1;
  1299.   gint32 layer_ID;
  1300.   GDrawable *drawable;
  1301.   guchar *pixelp;
  1302.   gulong pixel;
  1303.   guint start, end, scanlines;
  1304.   guchar *buf, *bufp;
  1305.   GdkColor *colors;
  1306.   guchar *rtbl, *gtbl, *btbl;
  1307.   guint rmask, gmask, bmask, rshift, gshift, bshift;
  1308.  
  1309.   int argc;
  1310.   char **argv;
  1311.  
  1312.   argc = 1;
  1313.   argv = g_new (char*, 1);
  1314.   argv[0] = g_strdup ("wmf");
  1315.  
  1316.   gdk_init (&argc, &argv);
  1317.  
  1318.   fp = fopen (filename, "rb");
  1319.   if (!fp)
  1320.     {
  1321.       g_message ("WMF: can't open \"%s\"", filename);
  1322.       return -1;
  1323.     }
  1324.  
  1325.   name_buf = g_malloc (strlen (filename) + 100);
  1326.   sprintf (name_buf, "Interpreting %s:", filename);
  1327.   gimp_progress_init (name_buf);
  1328.   g_free (name_buf);
  1329.  
  1330.   if (!ReadOK (fp, buffer, SIZE_WMFHEAD))
  1331.     {
  1332.       g_message ("WMF: Failed to read metafile header");
  1333.       return -1;
  1334.     }
  1335.  
  1336.   memmove (&apm_head.Key, buffer, 4);
  1337.   
  1338.   if (GUINT32_FROM_LE (apm_head.Key) == 0x9ac6cdd7)
  1339.     {
  1340.       if (!ReadOK (fp, buffer + SIZE_WMFHEAD,
  1341.            SIZE_PLACEABLEMETAHEADER - SIZE_WMFHEAD))
  1342.     {
  1343.       g_message ("WMF: Failed to read placeable metafile header");
  1344.       return -1;
  1345.     }
  1346.       memmove (&apm_head.Left, buffer + 6, 2);
  1347.       memmove (&apm_head.Top, buffer + 8, 2);
  1348.       memmove (&apm_head.Right, buffer + 10, 2);
  1349.       memmove (&apm_head.Bottom, buffer + 12, 2);
  1350.       memmove (&apm_head.Inch, buffer + 14, 2);
  1351.       bbox.x = GINT16_FROM_LE (apm_head.Left);
  1352.       bbox.y = GINT16_FROM_LE (apm_head.Top);
  1353.       bbox.width = GUINT16_FROM_LE (apm_head.Right) - bbox.x;
  1354.       bbox.height = GUINT16_FROM_LE (apm_head.Bottom) - bbox.y;
  1355.       have_bbox = TRUE;
  1356.       units_per_in = GUINT16_FROM_LE (apm_head.Inch);
  1357.  
  1358.       if (!ReadOK (fp, buffer, SIZE_WMFHEAD))
  1359.     {
  1360.       g_message ("WMF: Failed to read metafile header");
  1361.       return -1;
  1362.     }
  1363.     }
  1364.   else
  1365.     {
  1366.       units_per_in = 1440;
  1367.     }
  1368.   viewport.org_x = viewport.org_y = 0;
  1369.   viewport.valid = FALSE;
  1370.   window.org_x = window.org_y = 0;
  1371.   window.valid = FALSE;
  1372.  
  1373. #ifdef GTK_HAVE_FEATURES_1_1_2
  1374.   pixs_per_in = (int) (25.4 * gdk_screen_width () / gdk_screen_width_mm ());
  1375. #else
  1376.   pixs_per_in = 72;
  1377. #endif
  1378.  
  1379.   memmove (&wmf_head.Version, buffer + 4, 2);
  1380.   memmove (&wmf_head.FileSize, buffer + 6, 4);
  1381.   memmove (&wmf_head.NumOfObjects, buffer + 10, 2);
  1382.  
  1383.   if (GUINT16_FROM_LE (wmf_head.Version) != 0x0300)
  1384.     {
  1385.       g_message ("WMF: Metafile has wrong version, got %#x, expected 0x300",
  1386.          GUINT16_FROM_LE (wmf_head.Version));
  1387.       return -1;
  1388.     }
  1389.  
  1390.   nobjects = GUINT16_FROM_LE (wmf_head.NumOfObjects);
  1391.   objects = g_new (Object*, nobjects);
  1392.   for (i = 0; i < nobjects; i++)
  1393.     objects[i] = NULL;
  1394.  
  1395.   while (1)
  1396.     {
  1397.       if (!ReadOK (fp, buffer, SIZE_WMFRECORD))
  1398.     {
  1399.       g_message ("WMF: Failed to read metafile record");
  1400.       return -1;
  1401.     }
  1402.       memmove (&record.Size, buffer, 4);
  1403.       memmove (&record.Function, buffer + 4, 2);
  1404.       record_counter++;
  1405. #if 0
  1406.       g_print ("%#x %d\n", GUINT16_FROM_LE (record.Function), GUINT32_FROM_LE (record.Size));
  1407. #endif
  1408.       switch (GUINT16_FROM_LE (record.Function))
  1409.     {
  1410.     case SetWindowOrg:
  1411.       if (!readparams (record.Size, 2, fp, params))
  1412.         return -1;
  1413.       window.org_y = GINT16_FROM_LE (params[0]);
  1414.       window.org_x = GINT16_FROM_LE (params[1]);
  1415.       sync_record (record.Size, 2, fp);
  1416.       break;
  1417.  
  1418.     case SetViewportOrg:
  1419.       if (!readparams (record.Size, 2, fp, params))
  1420.         return -1;
  1421.       viewport.org_y = GINT16_FROM_LE (params[0]);
  1422.       viewport.org_x = GINT16_FROM_LE (params[1]);
  1423.       sync_record (record.Size, 2, fp);
  1424.       break;
  1425.  
  1426.     case SetWindowExt:
  1427.       if (!readparams (record.Size, 2, fp, params))
  1428.         return -1;
  1429.       window.ext_y = GINT16_FROM_LE (params[0]);
  1430.       window.ext_x = GINT16_FROM_LE (params[1]);
  1431.       window.valid = TRUE;
  1432.       sync_record (record.Size, 2, fp);
  1433.       break;
  1434.  
  1435.     case SetViewportExt:
  1436.       if (!readparams (record.Size, 2, fp, params))
  1437.         return -1;
  1438.       viewport.ext_y = GINT16_FROM_LE (params[0]);
  1439.       viewport.ext_x = GINT16_FROM_LE (params[1]);
  1440.       viewport.valid = TRUE;
  1441.       sync_record (record.Size, 2, fp);
  1442.       break;
  1443.  
  1444.     case IntersectClipRect:
  1445.       if (!readparams (record.Size, 4, fp, params))
  1446.         return -1;
  1447.       /* XXX */
  1448.       sync_record (record.Size, 4, fp);
  1449.       break;
  1450.       
  1451.     case SaveDC:
  1452.       dc = g_new (DC, 1);
  1453.       if (canvas == NULL)
  1454.         canvas = make_canvas (&window, &viewport, have_bbox, &bbox, units_per_in);
  1455.       *dc = canvas->dc;
  1456.       dc->gc = gdk_gc_new (canvas->pixmap);
  1457.       dc->tag = saved_dc_tag++;
  1458.       gdk_gc_copy (dc->gc, canvas->dc.gc);
  1459.       gdk_font_ref (dc->font->font);
  1460.       canvas->dc_stack = g_slist_prepend (canvas->dc_stack, dc);
  1461.       sync_record (record.Size, 0, fp);
  1462.       break;
  1463.  
  1464.     case RestoreDC:
  1465.       if (!readparams (record.Size, 1, fp, params))
  1466.         return -1;
  1467.       ix = GINT16_FROM_LE (params[0]);
  1468.       if (ix >= 0)
  1469.         {
  1470.           fclose (fp);
  1471.           g_message ("WMF: RestoreDC with positive argument (%d)?", ix);
  1472.           return -1;
  1473.         }
  1474.       while (ix++ < 0)
  1475.         {
  1476.           if (canvas->dc_stack == NULL)
  1477.         {
  1478.           fclose (fp);
  1479.           g_message ("WMF: DC stack underflow");
  1480.           return -1;
  1481.         }
  1482.           gdk_gc_unref (canvas->dc.gc);
  1483.           gdk_font_unref (canvas->dc.font->font);
  1484.           canvas->dc = *((DC *) canvas->dc_stack->data);
  1485.           canvas->dc_stack = g_slist_next (canvas->dc_stack);
  1486.         }
  1487.       sync_record (record.Size, 1, fp);
  1488.       break;
  1489.  
  1490.     case SetBkColor:
  1491.       if (!readparams (record.Size, 2, fp, params))
  1492.         return -1;
  1493.       if (canvas == NULL)
  1494.         canvas = make_canvas (&window, &viewport, have_bbox, &bbox, units_per_in);
  1495.       set_color (params + 0, &canvas->dc.bg);
  1496.       if (!gdk_color_alloc (canvas->colormap, &canvas->dc.bg))
  1497.         {
  1498.           fclose (fp);
  1499.           g_message ("WMF: Couldn't allocate color");
  1500.           return -1;
  1501.         }
  1502.       sync_record (record.Size, 2, fp);
  1503.       break;
  1504.  
  1505.     case SetBkMode:
  1506.       if (!readparams (record.Size, 1, fp, params))
  1507.         return -1;
  1508.       switch (GINT16_FROM_LE (params[0]))
  1509.         {
  1510.         case TRANSPARENT:
  1511.           break;
  1512.         case OPAQUE:
  1513.           if (!warned_opaque)
  1514.         {
  1515.           g_message ("The WMF file contains SetBkMode (OPAQUE).\n"
  1516.                  "This is not supported, sorry. The resulting\n"
  1517.                  "image might not look quite right.");
  1518.           warned_opaque = TRUE;
  1519.         }
  1520.           break;
  1521.         default:
  1522.           fclose (fp);
  1523.           g_message ("WMF: Invalid case %d at line %d",
  1524.              GINT16_FROM_LE (params[0]), __LINE__);
  1525.           break;
  1526.         }
  1527.       sync_record (record.Size, 1, fp);
  1528.       break;
  1529.  
  1530.     case SetTextColor:
  1531.       if (!readparams (record.Size, 2, fp, params))
  1532.         return -1;
  1533.       if (canvas == NULL)
  1534.         canvas = make_canvas (&window, &viewport, have_bbox, &bbox, units_per_in);
  1535.       set_color (params + 0, &canvas->dc.textColor);
  1536.       if (!gdk_color_alloc (canvas->colormap, &canvas->dc.textColor))
  1537.         {
  1538.           fclose (fp);
  1539.           g_message ("WMF: Couldn't allocate color");
  1540.           return -1;
  1541.         }
  1542.       sync_record (record.Size, 2, fp);
  1543.       break;
  1544.  
  1545.     case SetTextAlign:
  1546.       if (!readparams (record.Size, 1, fp, params))
  1547.         return -1;
  1548.       /* XXX */
  1549.       sync_record (record.Size, 1, fp);
  1550.       break;
  1551.  
  1552.     case SetROP2:
  1553.       if (!readparams (record.Size, 1, fp, params))
  1554.         return -1;
  1555.       if (canvas == NULL)
  1556.         canvas = make_canvas (&window, &viewport, have_bbox, &bbox, units_per_in);
  1557.       switch (GUINT16_FROM_LE (params[0]))
  1558.         {
  1559.         case R2_COPYPEN:
  1560.           gdk_gc_set_function (canvas->dc.gc, GDK_COPY); break;
  1561.         case R2_NOT:
  1562.           gdk_gc_set_function (canvas->dc.gc, GDK_INVERT); break;
  1563.         case R2_XORPEN:
  1564.           gdk_gc_set_function (canvas->dc.gc, GDK_XOR); break;
  1565. #ifdef GDK_CLEAR        /* Other ROPs not in gdk 1.0 */
  1566.         case R2_BLACK:
  1567.           gdk_gc_set_function (canvas->dc.gc, GDK_CLEAR); break;
  1568.         case R2_MASKPEN:
  1569.           gdk_gc_set_function (canvas->dc.gc, GDK_AND); break;
  1570.         case R2_MASKPENNOT:
  1571.           gdk_gc_set_function (canvas->dc.gc, GDK_AND_REVERSE); break;
  1572.         case R2_MASKNOTPEN:
  1573.           gdk_gc_set_function (canvas->dc.gc, GDK_AND_INVERT); break;
  1574.         case R2_NOP:
  1575.           gdk_gc_set_function (canvas->dc.gc, GDK_NOOP); break;
  1576.         case R2_MERGEPEN:
  1577.           gdk_gc_set_function (canvas->dc.gc, GDK_OR); break;
  1578.         case R2_NOTXORPEN:
  1579.           gdk_gc_set_function (canvas->dc.gc, GDK_EQUIV); break;
  1580.         case R2_MERGEPENNOT:
  1581.           gdk_gc_set_function (canvas->dc.gc, GDK_OR_REVERSE); break;
  1582.         case R2_NOTCOPYPEN:
  1583.           gdk_gc_set_function (canvas->dc.gc, GDK_COPY_INVERT); break;
  1584.         case R2_MERGENOTPEN:
  1585.           gdk_gc_set_function (canvas->dc.gc, GDK_OR_INVERT); break;
  1586.         case R2_NOTMASKPEN:
  1587.           gdk_gc_set_function (canvas->dc.gc, GDK_NAND); break;
  1588.         case R2_WHITE:
  1589.           gdk_gc_set_function (canvas->dc.gc, GDK_SET); break;
  1590. #endif
  1591.         default:
  1592.           fclose (fp);
  1593.           g_message ("Invalid ROP2");
  1594.           return -1;
  1595.         }
  1596.       sync_record (record.Size, 1, fp);
  1597.       break;
  1598.  
  1599.     case SetStretchBltMode:
  1600.       if (!readparams (record.Size, 1, fp, params))
  1601.         return -1;
  1602.       /* XXX */
  1603.       sync_record (record.Size, 1, fp);
  1604.       break;
  1605.  
  1606.     case SetPolyFillMode:
  1607.       if (!readparams (record.Size, 1, fp, params))
  1608.         return -1;
  1609.       /* GDK has no way to set the fill rule of a GdkGC! */
  1610.       /* XXX */
  1611.       sync_record (record.Size, 1, fp);
  1612.       break;
  1613.  
  1614.     case SetMapMode:
  1615.       if (!readparams (record.Size, 1, fp, params))
  1616.         return -1;
  1617.       switch (GUINT16_FROM_LE (params[0]))
  1618.         {
  1619.         case MM_ANISOTROPIC:
  1620.         case MM_ISOTROPIC:
  1621.           break;
  1622.  
  1623.         case MM_HIENGLISH:
  1624.           units_per_in = 1000;
  1625.           goto set_window_and_viewport;
  1626.  
  1627.         case MM_HIMETRIC:
  1628.           units_per_in = 2540;
  1629.           goto set_window_and_viewport;
  1630.  
  1631.         case MM_LOENGLISH:
  1632.           units_per_in = 100;
  1633.           goto set_window_and_viewport;
  1634.  
  1635.         case MM_LOMETRIC:
  1636.           units_per_in = 254;
  1637.           goto set_window_and_viewport;
  1638.           
  1639.         case MM_TEXT:
  1640.           units_per_in = pixs_per_in;
  1641.           goto set_window_and_viewport;
  1642.  
  1643.         case MM_TWIPS:
  1644.           units_per_in = 1440;
  1645.  
  1646.         set_window_and_viewport:
  1647.           window.valid = TRUE;
  1648.           viewport.valid = TRUE;
  1649.           window.org_x = window.org_y =
  1650.         viewport.org_x = viewport.org_y = 0;
  1651.           window.ext_x = units_per_in * 4;
  1652.           window.ext_y = units_per_in * 3;
  1653.           viewport.ext_x = load_vals.scale * fabs (window.ext_x) / units_per_in * pixs_per_in;
  1654.           viewport.ext_y = load_vals.scale * fabs (window.ext_y) / units_per_in * pixs_per_in;
  1655.           break;
  1656.  
  1657.         default:
  1658.           fclose (fp);
  1659.           g_message ("WMF: Invalid case %d at line %d",
  1660.              GUINT16_FROM_LE (params[0]), __LINE__);
  1661.           return -1;
  1662.         }
  1663.       sync_record (record.Size, 1, fp);
  1664.       break;
  1665.  
  1666.     case SetRelabs:
  1667.       if (!readparams (record.Size, 1, fp, params))
  1668.         return -1;
  1669.       /* XXX */
  1670.       sync_record (record.Size, 1, fp);
  1671.       break;
  1672.  
  1673.     case CreatePenIndirect:
  1674.       if (!readparams (record.Size, 5, fp, params))
  1675.         return -1;
  1676.       if ((objp = new_object (OBJ_PEN, objects, nobjects)) == NULL)
  1677.         {
  1678.           fclose (fp);
  1679.           return -1;
  1680.         }
  1681.       objp->u.pen.invisible = FALSE;
  1682.       switch (GUINT16_FROM_LE (params[0]))
  1683.         {
  1684.         case PS_SOLID:
  1685.         case PS_INSIDEFRAME:
  1686.           objp->u.pen.style = GDK_LINE_SOLID;
  1687.           break;
  1688.           
  1689.         case PS_DASH:
  1690.         case PS_DOT:
  1691.         case PS_DASHDOT:
  1692.         case PS_DASHDOTDOT:
  1693.           objp->u.pen.style = GDK_LINE_ON_OFF_DASH;
  1694.           break;
  1695.  
  1696.         case PS_NULL:
  1697.           objp->u.pen.style = GDK_LINE_SOLID;
  1698.           objp->u.pen.invisible = TRUE;
  1699.           break;
  1700.  
  1701.         default:
  1702.           g_message ("WMF: Unrecognized pen style %#x",
  1703.              GUINT16_FROM_LE (params[0]));
  1704.           fclose (fp);
  1705.           return -1;
  1706.         }
  1707.       if (canvas == NULL)
  1708.         canvas = make_canvas (&window, &viewport, have_bbox, &bbox, units_per_in);
  1709.       objp->u.pen.width = (int) XSCALE (GUINT16_FROM_LE (params[1]) + (GUINT16_FROM_LE (params[2]) << 16));
  1710.  
  1711.       set_color (params+3, &objp->u.pen.color);
  1712.       if (!gdk_color_alloc (canvas->colormap, &objp->u.pen.color))
  1713.         {
  1714.           g_message ("WMF: Couldn't allocate color");
  1715.           fclose (fp);
  1716.           return -1;
  1717.         }
  1718.       /* CreatePenIndirect records sometimes have junk padding? */
  1719.       sync_record (record.Size, 5, fp);
  1720.       break;
  1721.  
  1722.     case CreateBrushIndirect:
  1723.       if (!readparams (record.Size, 4, fp, params))
  1724.         return -1;
  1725.       if ((objp = new_object (OBJ_BRUSH, objects, nobjects)) == NULL)
  1726.         {
  1727.           fclose (fp);
  1728.           return -1;
  1729.         }
  1730.       objp->u.brush.style = GUINT16_FROM_LE (params[0]);
  1731.       objp->u.brush.invisible = FALSE;
  1732.       if (objp->u.brush.style == BS_NULL)
  1733.         objp->u.brush.invisible = TRUE;
  1734.       set_color (params+1, &objp->u.brush.color);
  1735.       if (canvas == NULL)
  1736.         canvas = make_canvas (&window, &viewport, have_bbox, &bbox, units_per_in);
  1737.       if (!gdk_color_alloc (canvas->colormap, &objp->u.brush.color))
  1738.         {
  1739.           g_message ("WMF: Couldn't allocate color");
  1740.           fclose (fp);
  1741.           return -1;
  1742.         }
  1743.       objp->u.brush.hatch = GUINT16_FROM_LE (params[3]);
  1744.       sync_record (record.Size, 4, fp);
  1745.       break;
  1746.       
  1747.     case DibCreatePatternBrush:
  1748.       if ((objp = new_object (OBJ_PATTERNBRUSH, objects, nobjects)) == NULL)
  1749.         {
  1750.           fclose (fp);
  1751.           return -1;
  1752.         }
  1753.       /* Ignored for now */
  1754.       sync_record (record.Size, 0, fp);
  1755.       break;
  1756.       
  1757.     case CreatePalette:
  1758.       if ((objp = new_object (OBJ_PALETTE, objects, nobjects)) == NULL)
  1759.         {
  1760.           fclose (fp);
  1761.           return -1;
  1762.         }
  1763.       /* XXX */
  1764.       sync_record (record.Size, 0, fp);
  1765.       break;
  1766.       
  1767.     case CreateFontIndirect:
  1768.       if (!readparams (record.Size, 9, fp, params))
  1769.         return -1;
  1770.       if ((objp = new_object (OBJ_FONT, objects, nobjects)) == NULL)
  1771.         {
  1772.           fclose (fp);
  1773.           return -1;
  1774.         }
  1775.       {
  1776.         gint height, orientation, weight, italic, pitch_family;
  1777.         char *pitch, *slant, *fontname, *name, *name2;
  1778.  
  1779.         height = ABS (GINT16_FROM_LE (params[0]));
  1780.         if (height == 0)
  1781.           height = 12;
  1782.         /* Orientation ignored for now. GDK doesn't support
  1783.          * tilted text anyway. We could of course rotate it by hand.
  1784.          */
  1785.         orientation = GUINT16_FROM_LE (params[2]);
  1786.         if (orientation != 0 && !warned_orientation)
  1787.           {
  1788.         g_message ("The WMF file contains non-horizontal fonts.\n"
  1789.                "This is not supported, sorry. The resulting\n"
  1790.                "image will not look quite right.");
  1791.         warned_orientation = TRUE;
  1792.           }
  1793.         weight = GUINT16_FROM_LE (params[4]);
  1794.         italic = (GUINT16_FROM_LE (params[5]) & 0xFF);
  1795.         pitch_family = ((GUINT16_FROM_LE (params[8]) >> 8) & 0xFF);
  1796.         if ((pitch_family & 0x03) == 1)
  1797.           pitch = "m";
  1798.         else if ((pitch_family & 0x03) == 2)
  1799.           pitch = "p";
  1800.         else
  1801.           pitch = "*";
  1802.  
  1803.         if (italic)
  1804.           {
  1805.         if ((pitch_family & 0x3) == 1)
  1806.           slant = "o";
  1807.         else
  1808.           slant = "i";
  1809.           }
  1810.         else
  1811.           slant = "r";
  1812.  
  1813.         k = GUINT32_FROM_LE (record.Size) - 9 - SIZE_WMFRECORD/2;
  1814.         name = g_malloc (k*2 + 1);
  1815.         for (i = 0; i < k*2; i++)
  1816.           {
  1817.         if ((i & 1) == 0)
  1818.           {
  1819.             if (!readparams (0, 1, fp, params))
  1820.               return -1;
  1821.             name[i] = (params[0] & 0xFF);
  1822.           }
  1823.         else
  1824.           name[i] = ((params[0] >> 8) & 0xFF);
  1825.           }
  1826.         name[k*2] = '\0';
  1827.  
  1828. #if 0
  1829.         g_print ("font name: %s\n", name);
  1830. #endif
  1831.         /* Very rough mapping from typical Windows fonts to XLFD */
  1832.         g_strdown (name);
  1833.         if (strcmp (name, "system") == 0)
  1834.           name2 = "courier";
  1835.         else if (strncmp (name, "arial", 5) == 0)
  1836.           name2 = "helvetica";
  1837.         else if (strncmp (name, "courier", 7) == 0)
  1838.           name2 = "courier";
  1839.         else
  1840.           name2 = name;
  1841.         fontname = g_malloc (200);
  1842.         sprintf (fontname, "-*-%s-%s-%s-%s-*-%d-*-*-*-%s-*-*-*",
  1843.              name2,
  1844.              (weight >= 700 ? "bold" :
  1845.               (weight >= 400 ? "medium" :
  1846.                "*")),
  1847.              slant,
  1848.              "*",
  1849.              (int) YSCALE (height),
  1850.              pitch);
  1851. #if 0
  1852.         g_print ("XLFD font: %s\n", fontname);
  1853. #endif
  1854.         objp->u.font.font = gdk_font_load (fontname);
  1855.         if (objp->u.font.font == NULL)
  1856.           {
  1857.         sprintf (fontname, "-*-%s-%s-%s-%s-*-%d-*-*-*-%s-*-*-*",
  1858.              "*",
  1859.              (weight >= 700 ? "bold" :
  1860.               (weight >= 400 ? "medium" :
  1861.                "*")),
  1862.              "*",
  1863.              "*",
  1864.              (int) YSCALE (height),
  1865.              "*");
  1866. #if 0
  1867.         g_print ("Another XLFD font: %s\n", fontname);
  1868. #endif
  1869.         objp->u.font.font = gdk_font_load (fontname);
  1870.         if (objp->u.font.font == NULL)
  1871.           {
  1872.             fclose (fp);
  1873.             g_message ("WMF: Cannot load suitable font, not even %s",
  1874.                    fontname);
  1875.             return -1;
  1876.           }
  1877.           }
  1878.         g_free (name);
  1879.         g_free (fontname);
  1880.       }
  1881.       break;
  1882.       
  1883.     case SelectObject:
  1884.       if (!readparams (record.Size, 1, fp, params))
  1885.         return -1;
  1886.       k = GUINT16_FROM_LE (params[0]);
  1887.       if (k >= nobjects)
  1888.         {
  1889.           fclose (fp);
  1890.           g_message ("WMF: Selecting out of bounds object index");
  1891.           return -1;
  1892.         }
  1893.       objp = objects[k];
  1894.       if (objp == NULL)
  1895.         {
  1896.           fclose (fp);
  1897.           g_message ("WMF: Selecting NULL object");
  1898.           return -1;
  1899.         }
  1900.       switch (objp->type)
  1901.         {
  1902.         case OBJ_BRUSH:
  1903.           if (canvas == NULL)
  1904.         canvas = make_canvas (&window, &viewport, have_bbox, &bbox, units_per_in);
  1905.           canvas->dc.brush = &objp->u.brush;
  1906.           break;
  1907.  
  1908.         case OBJ_PEN:
  1909.           if (canvas == NULL)
  1910.         canvas = make_canvas (&window, &viewport, have_bbox, &bbox, units_per_in);
  1911.           canvas->dc.pen = &objp->u.pen;
  1912.           gdk_gc_get_values (canvas->dc.gc, &gc_values);
  1913.           gdk_gc_set_line_attributes
  1914.         (canvas->dc.gc, objp->u.pen.width, objp->u.pen.style,
  1915.          gc_values.cap_style, gc_values.join_style);
  1916.           break;
  1917.  
  1918.         case OBJ_PATTERNBRUSH:
  1919.           /* XXX */
  1920.           break;
  1921.  
  1922.         case OBJ_FONT:
  1923.           gdk_font_unref (canvas->dc.font->font);
  1924.           canvas->dc.font = &objp->u.font;
  1925.           gdk_font_ref (canvas->dc.font->font);
  1926.           break;
  1927.  
  1928.         default:
  1929.           fclose (fp);
  1930.           g_message ("WMF: Unhandled case %d at line %d",
  1931.              objp->type, __LINE__);
  1932.           return -1;
  1933.         }
  1934.       sync_record (record.Size, 1, fp);
  1935.       break;
  1936.  
  1937.     case SelectPalette:
  1938.       if (!readparams (record.Size, 1, fp, params))
  1939.         return -1;
  1940.       k = GUINT16_FROM_LE (params[0]);
  1941.       if (k >= nobjects)
  1942.         {
  1943.           fclose (fp);
  1944.           g_message ("WMF: Selecting out of bounds palette index");
  1945.           return -1;
  1946.         }
  1947.       objp = objects[k];
  1948.       if (objp == NULL)
  1949.         {
  1950.           fclose (fp);
  1951.           g_message ("WMF: Selecting NULL palette");
  1952.           return -1;
  1953.         }
  1954.       if (objp->type != OBJ_PALETTE)
  1955.         {
  1956.           fclose (fp);
  1957.           g_message ("WMF: SelectPalette selects non-palette");
  1958.           return -1;
  1959.         }
  1960.       /* XXX */
  1961.       sync_record (record.Size, 1, fp);
  1962.       break;
  1963.  
  1964.     case RealizePalette:
  1965.       /* XXX */
  1966.       sync_record (record.Size, 0, fp);
  1967.       break;
  1968.  
  1969.     case DeleteObject:
  1970.       if (!readparams (record.Size, 1, fp, params))
  1971.         return -1;
  1972.       k = GUINT16_FROM_LE (params[0]);
  1973.       if (k >= nobjects)
  1974.         {
  1975.           fclose (fp);
  1976.           g_message ("WMF: Deleting out of bounds object index");
  1977.           return -1;
  1978.         }
  1979.       objp = objects[k];
  1980.       if (objp == NULL)
  1981.         {
  1982.           fclose (fp);
  1983.           g_message ("WMF: Deleting already deleted object");
  1984.           return -1;
  1985.         }
  1986.       if (objp->type == OBJ_FONT)
  1987.         gdk_font_unref (objp->u.font.font);
  1988.       g_free (objp);
  1989.       objects[k] = NULL;
  1990.       break;
  1991.       
  1992.     case MoveTo:
  1993.       if (!readparams (record.Size, 2, fp, params))
  1994.         return -1;
  1995.       if (canvas == NULL)
  1996.         canvas = make_canvas (&window, &viewport, have_bbox, &bbox, units_per_in);
  1997.       canvas->curx = XMAPPAR (params[1]);
  1998.       canvas->cury = YMAPPAR (params[0]);
  1999.       sync_record (record.Size, 2, fp);
  2000.       break;
  2001.  
  2002.     case LineTo:
  2003.       if (!readparams (record.Size, 2, fp, params))
  2004.         return -1;
  2005.       if (canvas == NULL)
  2006.         canvas = make_canvas (&window, &viewport, have_bbox, &bbox, units_per_in);
  2007.       x = XMAPPAR (params[1]);
  2008.       y = YMAPPAR (params[0]);
  2009.       gdk_draw_line (canvas->pixmap, canvas->dc.gc,
  2010.              (gint) canvas->curx, (gint) canvas->cury,
  2011.              (gint) x, (gint) y);
  2012.       canvas->curx = x;
  2013.       canvas->cury = y;
  2014.       sync_record (record.Size, 2, fp);
  2015.       break;
  2016.  
  2017.     case Polyline:
  2018.       if (!readparams (record.Size, 1, fp, params))
  2019.         return -1;
  2020.       npoints = GUINT16_FROM_LE (params[0]);
  2021.       points = g_new (GdkPoint, npoints);
  2022.       for (i = 0; i < npoints; i++)
  2023.         {
  2024.           if (!readparams (0, 2, fp, params))
  2025.         return -1;
  2026.           points[i].x = XIMAPPAR (params[0]);
  2027.           points[i].y = YIMAPPAR (params[1]);
  2028.         }
  2029.       if (canvas == NULL)
  2030.         canvas = make_canvas (&window, &viewport, have_bbox, &bbox, units_per_in);
  2031.       gdk_gc_set_foreground (canvas->dc.gc, &canvas->dc.pen->color);
  2032.       gdk_draw_lines (canvas->pixmap, canvas->dc.gc, points, npoints);
  2033.       g_free (points);
  2034.       break;
  2035.       
  2036.     case Rectangle:
  2037.       if (!readparams (record.Size, 4, fp, params))
  2038.         return -1;
  2039.       if (canvas == NULL)
  2040.         canvas = make_canvas (&window, &viewport, have_bbox, &bbox, units_per_in);
  2041.       if (!canvas->dc.brush->invisible)
  2042.         {
  2043.           gdk_gc_set_foreground (canvas->dc.gc, &canvas->dc.brush->color);
  2044.           gdk_draw_rectangle (canvas->pixmap, canvas->dc.gc, TRUE,
  2045.                   XIMAPPAR (params[3]),
  2046.                   YIMAPPAR (params[2]),
  2047.                   XIMAPPAR (params[1]) - XIMAPPAR (params[3]),
  2048.                   YIMAPPAR (params[2]) - YIMAPPAR (params[2]));
  2049.         }
  2050.       if (!canvas->dc.pen->invisible)
  2051.         {
  2052.           gdk_gc_set_foreground (canvas->dc.gc, &canvas->dc.pen->color);
  2053.           gdk_draw_rectangle (canvas->pixmap, canvas->dc.gc, FALSE,
  2054.                   XIMAPPAR (params[3]),
  2055.                   YIMAPPAR (params[2]),
  2056.                   XIMAPPAR (params[1]) - XIMAPPAR (params[3]),
  2057.                   YIMAPPAR (params[2]) - YIMAPPAR (params[2]));
  2058.         }
  2059.       sync_record (record.Size, 4, fp);
  2060.       break;
  2061.  
  2062.     case Ellipse:
  2063.       if (!readparams (record.Size, 4, fp, params))
  2064.         return -1;
  2065.       if (canvas == NULL)
  2066.         canvas = make_canvas (&window, &viewport, have_bbox, &bbox, units_per_in);
  2067.       if (!canvas->dc.brush->invisible)
  2068.         {
  2069.           gdk_gc_set_foreground (canvas->dc.gc, &canvas->dc.brush->color);
  2070.           gdk_draw_arc (canvas->pixmap, canvas->dc.gc, TRUE,
  2071.                 XIMAPPAR (params[3]),
  2072.                 YIMAPPAR (params[2]),
  2073.                 XIMAPPAR (params[1]) - XIMAPPAR (params[3]),
  2074.                 YIMAPPAR (params[0]) - YIMAPPAR (params[2]),
  2075.                 0, 360 * 64);
  2076.         }
  2077.       if (!canvas->dc.pen->invisible)
  2078.         {
  2079.           gdk_gc_set_foreground (canvas->dc.gc, &canvas->dc.pen->color);
  2080.           gdk_draw_arc (canvas->pixmap, canvas->dc.gc, FALSE,
  2081.                 XIMAPPAR (params[3]),
  2082.                 YIMAPPAR (params[2]),
  2083.                 XIMAPPAR (params[1]) - XIMAPPAR (params[3]),
  2084.                 YIMAPPAR (params[0]) - YIMAPPAR (params[2]),
  2085.                 0, 360 * 64);
  2086.         }
  2087.       sync_record (record.Size, 4, fp);
  2088.       break;
  2089.  
  2090.     case Polygon:
  2091.       if (!readparams (record.Size, 1, fp, params))
  2092.         return -1;
  2093.       npoints = GUINT16_FROM_LE (params[0]);
  2094.       points = g_new (GdkPoint, npoints);
  2095.       for (i = 0; i < npoints; i++)
  2096.         {
  2097.           if (!readparams (0, 2, fp, params))
  2098.         return -1;
  2099.           points[i].x = XIMAPPAR (params[0]);
  2100.           points[i].y = YIMAPPAR (params[1]);
  2101.         }
  2102.       if (canvas == NULL)
  2103.         canvas = make_canvas (&window, &viewport, have_bbox, &bbox, units_per_in);
  2104.       if (!canvas->dc.brush->invisible)
  2105.         {
  2106.           gdk_gc_set_foreground (canvas->dc.gc, &canvas->dc.brush->color);
  2107.           gdk_draw_polygon (canvas->pixmap, canvas->dc.gc, TRUE, points, npoints);
  2108.         }
  2109.       if (!canvas->dc.pen->invisible)
  2110.         {
  2111.           gdk_gc_set_foreground (canvas->dc.gc, &canvas->dc.pen->color);
  2112.           gdk_draw_polygon (canvas->pixmap, canvas->dc.gc, FALSE, points, npoints);
  2113.         }
  2114.       g_free (points);
  2115.       break;
  2116.  
  2117.     case PolyPolygon:
  2118.       if (!readparams (record.Size, 1, fp, params))
  2119.         return -1;
  2120.       if (canvas == NULL)
  2121.         canvas = make_canvas (&window, &viewport, have_bbox, &bbox, units_per_in);
  2122.       /* Number of polygons */
  2123.       npolys = GUINT16_FROM_LE (params[0]);
  2124.       nppoints = g_new (int, npolys);
  2125.       for (i = 0; i < npolys; i++)
  2126.         {
  2127.           if (!readparams (0, 1, fp, params))
  2128.         return -1;
  2129.           nppoints[i] = GUINT16_FROM_LE (params[0]);
  2130.         }
  2131.       for (i = 0; i < npolys; i++)
  2132.         {
  2133.           points = g_new (GdkPoint, nppoints[i]);
  2134.           for (j = 0; j < nppoints[i]; j++)
  2135.         {
  2136.           if (!readparams (0, 2, fp, params))
  2137.             return -1;
  2138.           points[j].x = XIMAPPAR (params[0]);
  2139.           points[j].y = YIMAPPAR (params[1]);
  2140.         }
  2141.           if (!canvas->dc.brush->invisible)
  2142.         {
  2143.           gdk_gc_set_foreground (canvas->dc.gc, &canvas->dc.brush->color);
  2144.           gdk_draw_polygon (canvas->pixmap, canvas->dc.gc,
  2145.                     TRUE, points, nppoints[i]);
  2146.         }
  2147.           if (!canvas->dc.pen->invisible)
  2148.         {
  2149.           gdk_gc_set_foreground (canvas->dc.gc, &canvas->dc.pen->color);
  2150.           gdk_draw_polygon (canvas->pixmap, canvas->dc.gc,
  2151.                     TRUE, points, nppoints[i]);
  2152.         }
  2153.           g_free (points);
  2154.         }
  2155.       g_free (nppoints);
  2156.       break;
  2157.  
  2158.     case TextOut:
  2159.       if (!readparams (record.Size, 1, fp, params))
  2160.         return -1;
  2161.       k = GUINT16_FROM_LE (params[0]);
  2162.       string = g_malloc (k);
  2163.       for (i = 0; i < k; i++)
  2164.         {
  2165.           if ((i & 1) == 0)
  2166.         {
  2167.           if (!readparams (0, 1, fp, params))
  2168.             return -1;
  2169.           j++;
  2170.           string[i] = (params[0] & 0xFF);
  2171.         }
  2172.           else
  2173.         string[i] = ((params[0] >> 8) & 0xFF);
  2174.         }
  2175.       if (!readparams (0, 2, fp, params))
  2176.         return -1;
  2177.       x = XMAPPAR (params[1]);
  2178.       y = YMAPPAR (params[0]);
  2179.       gdk_gc_set_foreground (canvas->dc.gc, &canvas->dc.textColor);
  2180.       gdk_draw_text (canvas->pixmap, canvas->dc.font->font,
  2181.              canvas->dc.gc, (gint) x, (gint) y, string, k);
  2182.       g_free (string);
  2183.       break;
  2184.  
  2185.     case ExtTextOut:
  2186.       if (!readparams (record.Size, 4, fp, params))
  2187.         return -1;
  2188.       /* Count words read */
  2189.       j = SIZE_WMFRECORD/2 + 4;
  2190.       x = XMAPPAR (params[1]);
  2191.       y = YMAPPAR (params[0]);
  2192.       /* String length ? */
  2193.       k = GUINT16_FROM_LE (params[2]);
  2194.       /* What is the fourth parameter? */
  2195.       string = g_malloc (k);
  2196.       for (i = 0; i < k; i++)
  2197.         {
  2198.           if ((i & 1) == 0)
  2199.         {
  2200.           if (!readparams (0, 1, fp, params))
  2201.             return -1;
  2202.           j++;
  2203.           string[i] = (params[0] & 0xFF);
  2204.         }
  2205.           else
  2206.         string[i] = ((params[0] >> 8) & 0xFF);
  2207.         }
  2208.       gdk_gc_set_foreground (canvas->dc.gc, &canvas->dc.textColor);
  2209.       /* ExtTextOut records can have an optional list of distances
  2210.        * between characters.
  2211.        */
  2212.       if (j < GUINT16_FROM_LE (record.Size))
  2213.         for (i = 0; i < k; i++)
  2214.           {
  2215.         gdk_draw_text (canvas->pixmap, canvas->dc.font->font,
  2216.                    canvas->dc.gc, (gint) x, (gint) y,
  2217.                    string + i, 1);
  2218.         if (j < GUINT16_FROM_LE (record.Size))
  2219.           if (!readparams (0, 1, fp, params))
  2220.             return -1;
  2221.         x += (int) XSCALE (GINT16_FROM_LE (params[0]));
  2222.           }
  2223.       else
  2224.         gdk_draw_text (canvas->pixmap, canvas->dc.font->font,
  2225.                canvas->dc.gc, (gint) x, (gint) y, string, k);
  2226.       g_free (string);
  2227.       break;
  2228.           
  2229.     case EndOfFile:
  2230.       fclose (fp);
  2231.       gimp_progress_update (1.0);
  2232.       
  2233.       if (canvas->height >= 100)
  2234.         {
  2235.           name_buf = g_malloc (strlen (filename) + 100);
  2236.           sprintf (name_buf, "Transferring image");
  2237.           gimp_progress_init (name_buf);
  2238.           g_free (name_buf);
  2239.         }
  2240.       
  2241.       image_ID = gimp_image_new (canvas->width, canvas->height, RGB);
  2242.       gimp_image_set_filename (image_ID, filename);
  2243.       layer_ID = gimp_layer_new (image_ID, "Background",
  2244.                      canvas->width, canvas->height, RGB_IMAGE,
  2245.                      100, NORMAL_MODE);
  2246.       gimp_image_add_layer (image_ID, layer_ID, 0);
  2247.       drawable = gimp_drawable_get (layer_ID);
  2248.       image = gdk_image_get (canvas->pixmap, 0, 0,
  2249.                  canvas->width, canvas->height);
  2250.       gimp_pixel_rgn_init (&pixel_rgn, drawable, 0, 0,
  2251.                    drawable->width, drawable->height,
  2252.                    TRUE, FALSE);
  2253.       if (pixel_rgn.bpp != 3)
  2254.         abort ();
  2255.       visual = gdk_visual_get_system ();
  2256.       switch (visual->type)
  2257.         {
  2258.         case GDK_VISUAL_PSEUDO_COLOR:
  2259.           buf = g_malloc (gimp_tile_height() * canvas->width * 3);
  2260.           colors = canvas->colormap->colors;
  2261.           for (j = 0; j < canvas->height;)
  2262.         {
  2263.           start = j;
  2264.           end = MIN (j + gimp_tile_height (), canvas->height);
  2265.           scanlines = end - start;
  2266.           bufp = buf;
  2267.  
  2268.           for (jj = 0; jj < scanlines; jj++)
  2269.             {
  2270.               pixelp = ((guchar *) image->mem) + (j + jj) * image->bpl;
  2271.               for (i = 0; i < canvas->width; i++)
  2272.             {
  2273.               *bufp++ = colors[*pixelp].red >> 8;
  2274.               *bufp++ = colors[*pixelp].green >> 8;
  2275.               *bufp++ = colors[*pixelp].blue >> 8;
  2276.               pixelp++;
  2277.             }
  2278.             }
  2279.           
  2280.           gimp_pixel_rgn_set_rect (&pixel_rgn, buf, 0, j, canvas->width, scanlines);
  2281.           if (canvas->height >= 100)
  2282.             gimp_progress_update ((double) j / canvas->height);
  2283.           j += scanlines;
  2284.         }
  2285.           if (canvas->height >= 100)
  2286.         gimp_progress_update (1.0);
  2287.           g_free (buf);
  2288.           break;
  2289.  
  2290.         case GDK_VISUAL_TRUE_COLOR:
  2291.           buf = g_malloc (gimp_tile_height () * canvas->width * 3);
  2292.  
  2293.           /* Set up mappings from subfield ranges to full 0..255 range */
  2294.           k = 1 << visual->red_prec;
  2295.           rtbl = g_malloc (k);
  2296.           for (i = 0; i < k; i++)
  2297.         rtbl[i] = (i * 255) / (k-1);
  2298.           k = 1 << visual->green_prec;
  2299.           gtbl = g_malloc (k);
  2300.           for (i = 0; i < k; i++)
  2301.         gtbl[i] = (i * 255) / (k-1);
  2302.           k = 1 << visual->blue_prec;
  2303.           btbl = g_malloc (k);
  2304.           for (i = 0; i < k; i++)
  2305.         btbl[i] = (i * 255) / (k-1);
  2306. #if 0
  2307.           printf ("R: %.08x, %d, %d\n", visual->red_mask, visual->red_shift, visual->red_prec);
  2308.           printf ("G: %.08x, %d, %d\n", visual->green_mask, visual->green_shift, visual->green_prec);
  2309.           printf ("B: %.08x, %d, %d\n", visual->blue_mask, visual->blue_shift, visual->blue_prec);
  2310.           printf ("image->bpp = %d\n", image->bpp);
  2311. #endif
  2312.           rmask = visual->red_mask;
  2313.           gmask = visual->green_mask;
  2314.           bmask = visual->blue_mask;
  2315.           rshift = visual->red_shift;
  2316.           gshift = visual->green_shift;
  2317.           bshift = visual->blue_shift;
  2318.           
  2319.           if (image->depth > 8 && image->bpp == 1)
  2320.         {
  2321.           /* Workaround for bug in GDK */
  2322.           if (image->depth > 24)
  2323.             image->bpp = 4;
  2324.           else if (image->depth > 16)
  2325.             image->bpp = 3;
  2326.           else
  2327.             image->bpp = 2;
  2328.         }
  2329.           
  2330.           for (j = 0; j < canvas->height;)
  2331.         {
  2332.           start = j;
  2333.           end = MIN (j + gimp_tile_height (), canvas->height);
  2334.           scanlines = end - start;
  2335.           bufp = buf;
  2336.  
  2337.           for (jj = 0; jj < scanlines; jj++)
  2338.             {
  2339.               pixelp = ((guchar *) image->mem) + (j + jj) * image->bpl;
  2340.               for (i = 0; i < canvas->width; i++)
  2341.             {
  2342.               pixel = 0;
  2343.               if (visual->byte_order == GDK_LSB_FIRST)
  2344. #if 1
  2345.                 {
  2346.                   k = image->bpp - 1;
  2347.                   switch (k)
  2348.                 {
  2349.                 case 3:
  2350.                   pixel |= (pixelp[k--] << 24);
  2351.                 case 2:
  2352.                   pixel |= (pixelp[k--] << 16);
  2353.                 case 1:
  2354.                   pixel |= (pixelp[k--] << 8);
  2355.                 case 0:
  2356.                   pixel |= (pixelp[k--]);
  2357.                 }
  2358.                 }
  2359. #else
  2360.               for (k = 0; k < image->bpp; k++)
  2361.                 pixel |= (pixelp[k] << (k*8));
  2362. #endif
  2363.               else
  2364.                 for (k = 0; k < image->bpp; k++)
  2365.                   pixel |= (pixelp[image->bpp - k - 1] << (k*8));
  2366.               
  2367.               *bufp++ = rtbl[(pixel & rmask) >> rshift];
  2368.               *bufp++ = gtbl[(pixel & gmask) >> gshift];
  2369.               *bufp++ = btbl[(pixel & bmask) >> bshift];
  2370.               pixelp += image->bpp;
  2371.             }
  2372.             }
  2373.           gimp_pixel_rgn_set_rect (&pixel_rgn, buf, 0, j, canvas->width, scanlines);
  2374.           if (canvas->height >= 100)
  2375.             gimp_progress_update ((double) j / canvas->height);
  2376.           j += scanlines;
  2377.         }
  2378.           if (canvas->height >= 100)
  2379.         gimp_progress_update (1.0);
  2380.           g_free (buf);
  2381.           g_free (rtbl);
  2382.           g_free (gtbl);
  2383.           g_free (btbl);
  2384.           break;
  2385.  
  2386.         default:
  2387.           g_message ("Unsupported image visual");
  2388.           return -1;
  2389.         }
  2390.       gimp_drawable_flush (drawable);
  2391.       
  2392.       return image_ID;
  2393.  
  2394.     default:
  2395.       if (!warned_unhandled)
  2396.         {
  2397.           g_message ("WMF: Unhandled operation %#x. Check the web page\n"
  2398.              "http://www.iki.fi/tml/gimp/wmf/ for a possible new\n"
  2399.              "version of the wmf plug-in. (This is version %s).\n"
  2400.              "If you already have the latest version, please send\n"
  2401.              "the WMF file you tried to load to the wmf plug-in\n"
  2402.              "author, Tor Lillqvist <tml@iki.fi>, and he might\n"
  2403.              "try to add the missing feature. No promise that\n"
  2404.              "he has any interest any longer, of course.",
  2405.              GUINT16_FROM_LE (record.Function),
  2406.              VERSION);
  2407.           warned_unhandled = TRUE;
  2408.         }
  2409.       sync_record (record.Size, 0, fp);
  2410.     }
  2411.  
  2412.       if (record_counter % 10 == 0)
  2413.     gimp_progress_update (((double) ftell (fp) / 2)
  2414.                   / GUINT32_FROM_LE (wmf_head.FileSize));
  2415.     }
  2416.  
  2417.   /*NOTREACHED*/
  2418.   fclose (fp);
  2419.   return image_ID;
  2420. }
  2421.  
  2422. static gint
  2423. readparams (DWORD size,
  2424.         guint nparams,
  2425.         FILE *fp,
  2426.         WORD *params)
  2427. {
  2428.   gulong nwords;
  2429.  
  2430.   if (size != 0)
  2431.     {
  2432.       nwords = GUINT32_FROM_LE (size) - SIZE_WMFRECORD/2;
  2433.       
  2434.       if (nwords < nparams)
  2435.     {
  2436.       fclose (fp);
  2437.       g_message ("WMF: too small record?");
  2438.       return 0;
  2439.     }
  2440.     }
  2441.  
  2442.   if (nparams > NPARMWORDS)
  2443.     {
  2444.       fclose (fp);
  2445.       g_message ("WMF: too large record?");
  2446.       return 0;
  2447.     }
  2448.       
  2449.   if (nparams > 0 && !ReadOK (fp, params, nparams  * sizeof (WORD)))
  2450.     {
  2451.       fclose (fp);
  2452.       g_message ("WMF: Read failed");
  2453.       return 0;
  2454.     }
  2455.  
  2456.   return 1;
  2457. }
  2458.  
  2459. static void
  2460. sync_record (DWORD size,
  2461.          guint nparams,
  2462.          FILE *fp)
  2463. {
  2464.   gulong nwords;
  2465.  
  2466.   nwords = GUINT32_FROM_LE (size) - SIZE_WMFRECORD/2;
  2467.   if (nwords > nparams)
  2468.     fseek (fp, (nwords - nparams) * 2, SEEK_CUR);
  2469. }
  2470.  
  2471. char *g_strdown(char *in)
  2472.     {
  2473.     char *useme = in;
  2474.     while(*useme != '\0')
  2475.         {
  2476.         *useme = tolower(*useme);
  2477.         useme++;
  2478.         }
  2479.     return(in);
  2480.     }
  2481.  
  2482.